Skip to content

fermyon/experimental-azure-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Overview

If you have code running as an Azure Function, this guide will show you how to transform it into a portable, WebAssembly-powered application with sub-millisecond start up time that connects to your existing Azure resources (using the Spin developer tool).

This repository contains the source code for the WebAssembly component we created which formats and signs HTTP calls in the way Azure requires. We have also provided Terraform that will deploy an example Storage Container and Queue instance in Azure.

How to get help

We understand that integrating a new technology can be challenging. If you have questions or feedback, reach out to us on our Discord channel.

Prerequisites

We are assuming that you have familiarity with the topics below. If you are not familiar, we have included links to helpful resources.

Background

As it currently stands, Spin applications written in Go, Python, and JavaScript are not able to use their respective Azure SDKs. As a workaround, we have built Spin components that make HTTP calls directly to Azure's API endpoints for object storage and queue services, which can be integrated into a Spin app and accessed via internal HTTP calls.

The component was written to interact with Azure's blob and queue storage services. See Azure's documentation for API information on other Azure services.

Benefits of migrating from serverless to Spin

While function-as-a-service products (FaaS) like Azure Functions offer remarkable scalability and simplicity, they are not without their issues. Three significant pain points for FaaS customers are cost, cold-start times (how long it takes to have the code ready for execution), and vendor lock-in (you are forced to use a specific cloud provider because switching will cost too much money and/or time). Spin solves these problems by offering sub-millisecond cold-start times, a significant reduction in cost if deployed using Fermyon Platform for Kubernetes, and cloud-agnostic portability, meaning your applications can be run on any Kubernetes cluster running SpinKube.

When is Spin not a good alternative to serverless?

Although Spin offers some amazing features, there are some situations for which it may not be a good fit. For example, if FaaS is not severely impacting the cost to run your applications, or if cold-start times are not meaningfully affecting the performance of your applications. In these cases, the work required to migrate existing infrastructure to Spin may not be justified by the relatively small improvements in cost and performance. Another situation where Spin may not be a good fit is if your applications rely heavily on libraries which Spin doesn't yet support. It's not impossible to find workarounds (as we have with the Azure SDK); however, there are some libraries for which we have not been able to create a workaround (see our language guides for more information).

Using the WebAssembly component

In the spin.toml file of the Spin application to which you want to add the Azure component, you'll need to tell Spin that you want the component to be part of your app, and you'll need to give your application permission to make HTTP calls to the Azure component:

# Don't forget that the main application needs to have permission to access the Azure client component, so don't forget to add either 'http://localhost:3000' or 'http://azure-client.spin.internal' as an allowed outbound host (see https://developer.fermyon.com/spin/v2/http-outbound#local-service-chaining for more details)

[variables]
az_account_name = { required = true, secret = true }
az_shared_key = { required = true, secret = true }

[[trigger.http]]
# For defining a custom route, see article on structuring Spin applications: https://developer.fermyon.com/spin/v2/spin-application-structure
route = "/..."
component = "azure-client"

[component.azure-client]
# Be sure to use the current version of the package. 
source = { registry = "fermyon.com", package = "fermyon-experimental:azure-client", version = " 0.1.0" }
# If the app needs to access multiple storage accounts, use "https://*.{{blob|queue}}.core.windows.net"
allowed_outbound_hosts = [
    "https://{{ az_account_name }}.blob.core.windows.net", 
    "https://{{ az_account_name }}.queue.core.windows.net",
]

[component.azure-client]
az_account_name = "{{ az_account_name }}"
az_shared_key = "{{ az_shared_key }}"

Once these entries have been added to the spin.toml file, you can run spin build.

Building from source

Requirements

  • Latest version of Spin
  • Latest version of Go
  • Latest version of TinyGo

Building the component:

Navigate to the directory containing the code files, then run the below commands:

# Installing dependencies
go mod download
# Building the component
spin build

Running the application

Export environment variables

In your terminal, export the below variables:

export SPIN_VARIABLE_AZ_ACCOUNT_NAME=YOUR_ACCOUNT_NAME
export SPIN_VARIABLE_AZ_SHARED_KEY=YOUR_SHARED_KEY

Notice that the environment variables are formatted SPIN_VARIABLE_UPPERCASE_VARIABLE_NAME. This is the format required by Spin to read environment variables properly. As can be seen in the spin.toml file, the Spin application accesses the variables as lowercase_variable_name.

Once the environment variables have been exported, you can run spin up.

Interacting with the application:

The curl request examples below are for standalone Azure components. If trying to interact with the Azure component from within Spin, the commands will look a little different:

// Place blob
method := "PUT"
endpoint := "http://127.0.0.1:3000/azure-client/container-name/path/to/your/blob"
bodyData := []byte("Hello, Azure!")

req, err := http.NewRequest(method, endpoint, bytes.NewReader(bodyData))
if err != nil {
    panic(err)
}

req.Header.Set("x-az-service", "blob")

resp, err := spinhttp.Send(req)

List blobs:

curl \
    -H 'x-az-service: blob' \
    "http://127.0.0.1:3000/azure-client/container-name?restype=container&comp=list"

Get blob:

curl \
    -o file_name.extension \
    -H 'x-az-service: blob' \
    http://127.0.0.1:3000/azure-client/container-name/path/to/your/blob

Delete blob:

curl \
    --request DELETE \
    -H 'x-az-service: blob' \
    http://127.0.0.1:3000/azure-client/container-name/path/to/your/blob

Place blob:

curl \
    --request PUT \
    -H 'x-az-service: blob' \
    --data-binary @/path/to/file \
    http://127.0.0.1:3000/azure-client/container-name/path/to/your/blob

Get queue messages:

curl \
    -H 'x-az-service: queue' \
    http://127.0.0.1:3000/azure-client/your-queue-name/messages

Delete queue message:

# The message-id and pop-receipt string values can be retrieved via getting messages from the queue.
curl \
    --request DELETE \
    -H 'x-az-service: queue' \
    "http://127.0.0.1:3000/azure-client/your-queue-name/messages/your-message-id?popreceipt=your-pop-receipt-value"

Place queue message:

# Per their documentation, the request body needs to be formatted using the XML as follows:
# <QueueMessage>
#   <MessageText>YourMessageHere</MessageText>
# </QueueMessage>
curl \
    --request POST \
    -H 'x-az-service: queue' \
    --data-binary @path/to/your/xml/message \
    http://127.0.0.1:3000/azure-client/your-queue-name/messages

Testing

Requirements

  • Latest version of Go

Running the tests

In your terminal, in the root directory of the code files, run make test.

About

No description, website, or topics provided.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages