Skip to main content
Pure Technical Services

Using AWS Lambda to Automate Tasks for Pure Cloud Block Store

Currently viewing public documentation. Please login to access the full scope of documentation.

This document walks through the steps of how to use AWS Lambda to invoke scripts and execute them against Pure Cloud Block Store on AWS. 

Introduction

AWS Lambda is a serverless compute service that allows you to run code without the need for provisioning or managing servers. It allows you to package and upload your code along with its dependencies, and it can be run directly in the GUI code editor, using AWS CLI and API, or it can be trigger using subscribed events.

This guide objective is to create a Lambda that will serve as a skeleton function that can be reused for any use cases and integration points. It can be applied to achieve a certain task or multitasks on Cloud Block Store, and the function can be triggered automatically with event-driven approach or by scheduled events. 

The scripting method utilized in this guide to access and interact with CBS is by using Pure Python client SDK (refer to the latest SDK documentation here). This Python package provides clients that use the Pure1, FlashArray, and FlashBlade REST APIs. Therefore, If you have already created scripts using Pure Python SDK, it can be reused here using this approach. 

To name few of the use cases that can be automated with AWS Lambda: 

  • Creating new EC2 instance and attaching volumes from CBS. 
  • Expanding volumes when EC2 storage utilization hit a certain metric. 
  • Cleaning up the provisioned storage for Auto Scaling EC2 scale in actions
  • Replicating protection groups to second array 
  • Collecting performance metrics

Solution Workflow

Setting up the Lambda function requires a couple of steps, each are explained in details in the sections below: 

  • Creat API Client
  • Provide IAM permissions 
  • Package dependences to Lambda Layer 
  • Configure Lambda function
  • Run Lambda Function

Note: This guide provides instructions using AWS Console and AWS CLI. Alternatively, you can use Terraform by downloading the manifest files from this Github and update your environment variables in this file terraform.tfvars. 

Note: CLI instructions in this guide presumes you have installed AWS CLI on your local machine and configured/authenticated with your AWS account. 

Note: Another option for CLI instructions is to use AWS CloudShell, which can be accessed in AWS console.

clipboard_ed2a40dc703c05332c2dec363447c50a9.png


Create API Client 

In order to use Pure Python SDK, FlashArray/Cloud Block Store uses API Client method to authenticate to the array for REST access. The following steps produce the required parameters, which will be used in the Lambda function code later on. 

Generating a RSA key pair 

If you don't already have an RSA key pair available, generate one using the Linux commands below:

openssl genrsa -out cbsprivate.pem 2048
openssl rsa -in cbsprivate.pem -outform PEM -pubout -out cbspublic.pem

Display your new public key in plain text using the following command:

cat cbspublic.pem

You should see something similar to the following:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt7WqkyADURjdO9lPtNXW
4ihQ4FF/DDsSslJD7N9b8j5ghD5BJO543L2Nr96rh8Fa9pXpbSbiMGG67RQ695wK
uxrTdyhKQ8lZQuCEzX7+sUoNopeRK7vfsmiv+eT6g/wEFg4KBaTIrYKqPfEVw9Ub
0Ib1CjXHlx+DZdmff47ZrhOwaGQ4oYsJEKAA0Yc608b2yD9H84UN/uq/Ukh5Q7Th
3BtzY6LcQe5FrktQomH8AFCvzY7XBUao8iCPmg7jLnaFZmQpipslwoUpRfxDDD5L
7rO1OjR1GX2+3PInKYQ+ROoMp8MPUKCUU/pH4BDFAZF7A9W6H48bD2mnSjUnqwIp
gQIDAQAB
-----END PUBLIC KEY-----

Copy the public key plain text into your clipboard or in a separate document for future reference, and you will also need it in the next step. 

Creating an API Client 

To create an API client, SSH into your Cloud Block Store as a user with array admin privileges and enter the following command:

pureapiclient create --max-role array_admin --public-key <name_of_your_app>

Note: Each API Client has an Issuer value. The issuer for an API Client is the IdP that is associated with that API Client. The issuer defaults to the name of the API Client, but you can optionally user the --issuer argument to set it to a different value. In this guide, you will always be acting as the IdP (even though you might delegate the actual token creation to a script), so feel free to set the issuer to whatever you want, or leave it as the default.

Note: valid values for the --max-role parameter are: array_adminstorage_adminops_admin and readonly .

Note: you can also specify the optional  --access-token-ttl parameter, which specifies the time interval in which the issued access tokens are valid. Allowed values are between1000 (1 second) to 86400000 (1 day). The default value is 1 day.

When you press 'Enter' after typing the command above, you get prompted to enter your public key:

pureapiclient create --max-role array_admin --public-key myClient
Please enter public key followed by ^D:

Paste the public key plain text you retrieved with the cat fa2xpublic.pem  command above and press Enter. Then press Control+D.
Note: Only after pressing Enter should you press Control+D, otherwise, this won't work.

You should see an output similar to the following:

Name      Enabled  Max Role     Issuer    Access Token TTL  Client ID                             Key ID
myClient  False    array_admin  myClient  1d                ab18a763-2b34-4b61-aa8e-a45afc7ad945  e7d175d3-c88b-41ef-b5f9-79c75a53cd2e

As you may notice above, your API client is disabled by default, so you must enable it with the following command:

pureapiclient enable myClient

Name      Enabled  Role         Issuer    Access Token TTL  Client ID                             Key ID
myClient  True     array_admin  myClient  1d                ab18a763-2b34-4b61-aa8e-a45afc7ad945  e7d175d3-c88b-41ef-b5f9-79c75a53cd2e

Copy the details of your API Client in a separate document which will be paste to the python code later. 

Store Private Key in AWS System Manager Parameter Store

The private key generated in the previous step will be used by the Lambda function. Therefore, storing it in SSM Paramete Store helps retrieving it upon request securely and programmatically using AWS python SDK.  

In your local machine, run the below command after changing to the directory where the private key is located.

aws ssm put-parameter --name "/cbs/apiclient/privatekey" --value "$(cat cbsprivate.pem)" --type String

Provide IAM permissions

Lambda function is using IAM permissions to access and interact with AWS service. Therefore, we need to assign an execution role during the function creation that contains the required IAM polices. 

Create IAM Policy

First, follow this steps to create IAM policy using AWS console. 

  • In the navigation pane on the left side of the AWS console, choose Policies.
  • Click Create policy, then select JSON tab. 
  • Copy/Paste the below JSON formatted text below. Note: Replace the Resource (colored in green) by your parameter ARN. 
  • Review the policy and give it a name and a description, then Create policy. 
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        
        {
            "Effect": "Allow",
            "Action": "ssm:GetParameter",
            "Resource": "arn:aws:ssm:eu-central-1:xxxxxxxxxxx:parameter/cbs/apiclient/privatekey"
        }
    ]
}

Note: For ssm: GetParameter policy, It is Recommended specify only the resource "parameter" giving access to.  To get the ARN for the resource run the below command: 

aws ssm get-parameter --name "cbs"

Expected output:


{
    "Parameter": {
        "Name": "cbs",
        "Type": "String",
        "Value": "xxxxxxxxxx",
        "Version": 1,
        "LastModifiedDate": "2022-01-06T14:31:31.039000+01:00",
        "ARN": "arn:aws:ssm:eu-central-1:xxxxxxxxxxx:parameter/cbs/apiclient/privatekey",
        "DataType": "text"
    }
}

Create IAM Role

Once you have an IAM Policy, the next step is to create the execution role, which is carries these permissions and will be later assigned to the new created function. 

  • In the navigation pane on the left side of the IAM console, choose Roles, and then choose Create role.
  • For Select type of trusted entity, pick AWS service.
  • Under Attach permission policy, two policies to be attached:
    1. Search the newly created policy and select. 
    2. Search for AWSLambdaVPCAccessExecutionRole, this is an AWS managed policy, and it has all the permission needed to connect the Lambda function to a private VPC (The VPC which CBS resides).
  • Review the role and give it a name and a description, then Create role. 

Note: The sample IAM policy above is just an example and it gives permissions only to CloudWatch logs and System Manager Parameter Store, you can customize this policy later when adding triggers or requiring the function to access certain services or resources. 


Package Dependences to Lambda Layer 

Even though python runtime in Lambda comes with its own set of standard libraries, such as boto3, os, urllib3, etc ..., those libraries can be imported and used in your function. However, the troublesome arose when you want to use a specific library or libraries that are non-native python packages and not available with the default libraries that Lambda offers. For this guide case, py-pure-client library. 

AWS solves this with different approaches, for the sake of the reproducibility of the functions, Lambda layers has been chosen. Lambda Layer allows you to package your function code dependencies and third-party libraries in a .zip file and upload it as Lambda layer. Every function can reference up to 5 layers, and they can be shared publicly or with a specific AWS account. Therefore, this is what we will wrap the py-pure-client package into and then share it with the function.  

Note: Lambda uses Amazon Linux environment as its OS. Therefore, packages installed on Windows may not work. 

Since packaging might go wrong for a couple of reason (third-party libraries missing or mismatch in the dependencies). You can use the pre-packaged zip file uploaded to S3. 

https://pure-storage-kb-solutions.s3.eu-central-1.amazonaws.com/pure-python-lambda-layer/py-pure-client-runtime3.6.zip

Create Lambda Layer 

The Lambda layer created using the provided package, contains only the py-pure-client. if you want to add other libraries to your function, you can create up to 5 layers. Instructions on how to package library dependencies can be found here.   

AWS Console

Navigate to AWS Lambda and choose Layers from the left side pane, then click Create layer

clipboard_e9d2abc4ec7c7be92871fa3ff4cde87e2.png

Under Create layer choose the following: 

  1. Enter layer name.
  2. Enter description. 
  3. Select upload a file from Amazon S3, then Paste the S3 link URL provided above. 
  4. Choose x86_64 for the architecture. 
  5. Choose Python 3.6 for the runtime.

clipboard_e17818e69235b9f59ccaca1a4a584aad9.png

Click Create, and with this a layer has been created. The next step is to create a function and attach the layer to it. 

AWS CLI

In your local machine or AWS CloudShell, run the below command. You can change the layer-name and description (the parameters colored in green). DO NOT change the S3 content or compatibility-runtime.

aws lambda publish-layer-version \
    --layer-name my-layer \
    --description "My Python layer" \
    --content S3Bucket=pure-storage-kb-solutions,S3Key=pure-python-lambda-layer/py-pure-client-runtime3.6.zip \
    --compatible-runtimes python3.6

From the output JSON response, copy the LayerVersionArn to a separate document, so it can be added to the Lambda function later using the AWS CLI. 

Output response example: 

 {
    "Content": {
        "Location": "https://awslambda-us-east-2-layers.s3.us-east-2.amazonaws.com/snapshots/123456789012/my-layer-4aaa2fbb-ff77-4b0a-ad92-5b78a716a96a?versionId=27iWyA73cCAYqyH...",
        "CodeSha256": "tv9jJO+rPbXUUXuRKi7CwHzKtLDkDRJLB3cC3Z/ouXo=",
        "CodeSize": 169
    },
    "LayerArn": "arn:aws:lambda:us-east-2:123456789012:layer:my-layer",
    "LayerVersionArn": "arn:aws:lambda:us-east-2:123456789012:layer:my-layer:1",
    "Description": "My layer",
    "CreatedDate": "2018-11-14T23:03:52.894+0000",
    "Version": 1,
    "CompatibleArchitectures": [
        "arm64",
        "x86_64"
     ],
    "CompatibleRuntimes": [
        "python3.6"
    ]
}

Configure Lambda Function

Lambda function can created and updated by either using the Lambda console or Lambda API via AWS CLI. This section shows both approaches and provides sample code. 

Create Lambda Function

AWS Console

Navigate to AWS Lambda and choose Functions from the left side pane, then click Create function

clipboard_e283d689e0aed815dfb2df66183a50bf3.png

 

Under Create function choose the following: 

  1. Select Author from scratch. 
  2. Enter Function name. 
  3. Choose Python 3.6 for the runtime.
  4. Choose x86_64 for the architecture. 
  5. Under Permission, select Use an existing role, then from the dropdown choose the IAM role created in previous steps.  

clipboard_e6e2f4ffb615b6705e9952e7020084947.png

Click Create function, and with this a function has been created, next step is to configure the function networking and edit the code. 

clipboard_e96a3749c5f4087c74f75b467561a90b0.png

AWS CLI 

Run the below command by replacing with your function name and IAM role ARN. 

aws lambda create-function --function-name my-function \
--runtime python3.6 \
--architecture x86_64 \
--role arn:aws:iam::123456789012:role/cbs-lambda-role
--runtime 60
--memory-size 256 

Configure Networking

By default, Lambda functions runs in an isolated VPC managed by AWS. In order for the function to communicate with Cloud Block Store, you need to edit VPC configuration of your function by connecting it to the same VPC and subnet where your CBS management interface located, or to any VPC/subnet has routing to CBS. The steps to achieve this connection are the following: 

AWS Console 

In the function page, click on Configuration, then select VPC, then click Edit

clipboard_ea7f26b55a37a6668b2555951308d46d3.png

Enter the VPC, subnet, and security group. Then click Save

clipboard_e8a24581e01ac0e1ffdaf62a2d810f790.png

AWS CLI

Run the below command to configure the VPC network for the function. Replace with your function name, subnet ID, and security group ID. 

aws lambda update-function-configuration --function-name pure-cbs-function \
--vpc-config SubnetIds=subnet-0xxxxxxxxxxx,SecurityGroupIds=sg-0xxxxxxxxxxxxx

Upload Sample Code

AWS Console

Copy the sample code from the github link below, then paste the code into the code-editor, then click Deploy

https://github.com/PureStorage-OpenConnect/cloudblockstore-scripts/tree/main/aws/aws-lambda-python/sample-lambda-code

clipboard_e1ececcb8b44ba788d87f588694854358.png

AWS CLI

First, package your code file .py in a zip file then run lambda update function command below. 

where: 

cbs-function-lambda.zip is the name of the zip file

lambda_fucntion.py is the python file 

zip cbs-function-lambda.zip lambda_function.py 
aws lambda update-function-code --function-name pure-cbs-function --zip-file fileb://cbs-function-lambda.zip

Add Layer

The command below adds the previously created layer to the function. Make sure to paste the layer ARN copied in previous step.   

aws lambda update-function-configuration \
--function-name pure-cbs-function \
--layers arn:aws:lambda:xx-central-1:xxxxxxxx:layer:my-layer:1

Add Environment Variables

Lambda function can use environment variable that can be retrieved in the code, this will element the need to hard code variables and allow scripts to be reused. The command below adds the following as environment variables: Retrieve variables

CBS_IP: Array "CBS" management IP address

CBS_USERNAME: Array username with admin_access

CLIENT_ID: Client ID created in previous section Create Client API 

KEY_ID: Key ID created in previous section Create Client API 

CLIENT_API_ISSUER: Issuer created in previous section Create Client API 

aws lambda update-function-configuration --function-name pure-cbs-function \
--environment "Variables={CBS_IP='x.x.x.x',CBS_USERNAME='pureuser',CLIENT_ID='xxxxxxxxxx',KEY_ID='xxxxxxxxx',CLIENT_API_ISSUER='myClient'}"

 

Run Lambda Function 

Test Sample Script 

Go to the created function, then click Test

clipboard_eb8e76c073f9d1ced68488b43ca63c9b0.png

Test will take some time and then return with response, click on Execution results in the code-editor. 

clipboard_e1a9aaec30595a4ea97b6fa3929bd71a7.png 

Monitor with CloudWatch logs 

All Lambda invocations are automatically logged and stored with CloudWatch. Therefore, the logs generated by your code using logging statements can be found and accessed under Monitor tab or you can navigate to CloudWatch console. 

clipboard_e30da5a94c1d2366d3746e57010bf4797.png