Introducing provider-http: Empowering Crossplane with HTTP Interactions

Introduction

As technologies continue to evolve, Crossplane emerges as a powerful solution for managing infrastructure as code across multiple clouds and on-premises environments. One of the key features that makes Crossplane so versatile is its extensible architecture through providers. In this blog post, we'll dive into the world of provider-http, exploring its capabilities and demonstrating how it can enhance your infrastructure management.

Overview of provider-http

provider-http is a Crossplane Provider that brings the power of HTTP requests to Crossplane’s ecosystem. It introduces two key resources – DisposableRequest for one-time HTTP interactions and Request for managing resources through HTTP requests.

provider-http allows you to integrate HTTP requests, offering a straightforward approach to managing a diverse range of infrastructure within your control plane. Whether you're interacting with RESTful APIs or other HTTP endpoints, provider-http acts as your gateway to a multitude of possibilities.

provider-http was born out of my need to manage resources when no readily accessible provider was available. Leveraging the ubiquity of REST APIs, provider-http seamlessly bridges the gap, offering a practical and timely alternative without the need for developing a new provider from scratch.

Use Cases

One-Time Requests with DisposableRequest

Easily initiate one-time HTTP requests using the DisposableRequest managed resource. This is perfect for scenarios where a single interaction is required, providing flexibility and simplicity. It serves as a way to send a request that doesn't represent an actual resource—a convenient "send and forget" mechanism.

Resource Management with Request

Manage resources through HTTP requests by creating Request resources. Trigger POST requests on resource creation, PUT requests on updates, and DELETE requests when the resource is deleted. The provider-http ensures your resources are always in sync with their desired state.

Installation and Setup

Installing Crossplane

If you haven't already installed Crossplane, follow the official installation guide. Ensure that Crossplane is up and running before proceeding.

Deploying provider-http

Once Crossplane is installed, deploy provider-http by running the Crossplane CLI command:

crossplane xpkg install provider xpkg.upbound.io/crossplane-contrib/provider-http:v0.2.0

Demo: Automating API Calls with Crossplane and provider-http

Let's walk through in depth examples where we automate API calls using Crossplane and provider-http.

Send a slack message after bucket creation

Let’s imagine you're managing your cloud infrastructure using Crossplane, and alongside provisioning an AWS S3 bucket, you also want to notify your team on Slack about the successful creation. This is where the provider-http steps in to simplify the orchestration, allowing you to seamlessly integrate Slack notifications into your infrastructure provisioning.

To send a message to a Slack channel, we'll need to send an HTTP request to the endpoint https://slack.com/api/chat.postMessage. Below is an example composition using the DisposableRequest managed resource:

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
  resources:
    - name: s3-bucket
      base: 
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: "us-east-2"

    - name: notify-on-slack
      base:
        apiVersion: http.crossplane.io/v1alpha1
        kind: DisposableRequest
        metadata:
          name: notify  
        spec:
          deletionPolicy: Orphan
          forProvider:
            insecureSkipTLSVerify: true
            waitTimeout: 5m
            rollbackLimit: 5
            url:  https://slack.com/api/chat.postMessage
            method: POST
            body: |
              {
                "channel": "C1234567890",
                "text": "S3 bucket created successfully!"
              }
            headers:
              Authorization: 
                - "Bearer xxxx-xxxxxxxxx-xxxx"
              Content-Type: 
                - "application/x-www-form-urlencoded"
                - "application/json"
      patches:
        - type: ToCompositeFieldPath
          fromFieldPath: status.response.body
          toFieldPath: status.response.body
          transforms:
            - type: convert
              convert:
                toType: object
                format: json

Manage a Jira project through Crossplane

For the next example, let's consider a scenario where we aim to efficiently handle Jira projects. Jira projects, being stateful objects that we want to proactively manage, perfectly align with the capabilities of the Request managed resource provided by our provider-http.

apiVersion: http.crossplane.io/v1alpha1
kind: Request
metadata:
  name: jira-project
spec:
  forProvider:
    headers:
      Content-Type:
        - "application/json"
      Accept:
        - "application/json"
      Authorization:
        - "Basic BASE64_ENCODED_USER_CREDENTIALS"

    # `payload` defines a base URL and a reusable JSON body for HTTP requests,
    # enabling concise and centralized data management. The mappings section below
    # utilizes jq to dynamically generate URLs and request bodies based on the
    # data provided in the payload.

    payload:
      baseUrl: https://your-domain.atlassian.net/rest/api/3/project
      body: |
        {
          "description": "Cloud migration initiative",
          "name": "Example Project",
          "key": "Example Project"
        }

    mappings:
        # POST: Sent when creating the YAML
        # This creates a new Jira project with specified details.
      - method: "POST"
        url: .payload.baseUrl
        body: |
          {
            "name": .payload.body.name,
            "description": .payload.body.description,
            "key": .payload.body.key
          }

        # GET: Sent during reconciliation
        # If the specified PUT body is not present in the GET response, a PUT 
        # request will be sent to update the resource with the specified PUT body.
        # If the PUT body is already present in the GET response, the resource is 
        # considered up-to-date, and no PUT will be sent.
      - method: "GET"
        url: (.payload.baseUrl + "/" + (.response.body.id|tostring))
       
        # PUT: Sent during reconciliation when the body is not found in the GET 
        # response
        # This updates the Jira project details based on the specified PUT body.
      - method: "PUT"
        url: (.payload.baseUrl + "/" + (.response.body.id|tostring))
        body: |
          {
            "name": .payload.body.name,
            "description": .payload.body.description,
          }

        # DELETE: Sent when deleting the YAML
        # This deletes the Jira project specified in the YAML.
      - method: "DELETE"
        url: (.payload.baseUrl + "/" + (.response.body.id|tostring))

For more information regarding the parameters in the resources, refer to the provider-http documentation.

Conclusion

provider-http extends Crossplane's capabilities, opening up new possibilities for managing HTTP-based interactions within your infrastructure. Notably, its strength lies in addressing scenarios where resources lack an existing provider. It offers a swift and flexible solution for resource management without the need to develop a new provider from scratch.

As you explore the potential of provider-http, remember to share your experiences and insights with the growing Crossplane community. Happy automating!

Have questions, insights to share, or want to contribute to the ongoing development of provider-http? Feel free to join us via one of the following methods: