Saadati.CloudFlow: Streamlining Cloud & DevOps Workflows
You know, in the world of cloud infrastructure and DevOps, things can get pretty tangled pretty quickly. We're constantly juggling SDKs, CLIs, YAML files, and trying to stitch together robust, repeatable workflows. That's precisely the challenge I set out to tackle with Saadati.CloudFlow.
It's a library and accompanying command-line tool, born out of my own frustrations and experiences managing complex cloud deployments and CI/CD pipelines. My vision was simple: provide a cohesive, opinionated, and developer-friendly way to interact with common cloud services and orchestrate DevOps tasks, primarily focusing on the Azure ecosystem but with an eye towards broader cloud-agnostic principles. Think of it as your intelligent assistant for navigating the cloud jungle, allowing you to focus on what you want to achieve, not how to wrangle disparate tools.
If you've ever spent hours debugging a YAML pipeline or trying to figure out the "right" way to provision a resource programmatically, you'll immediately grasp the value Saadati.CloudFlow brings to the table. It's built on a foundation of C# and .NET, leveraging the power and familiarity of these tools to bring clarity and control to your cloud operations.
Features
I’ve packed Saadati.CloudFlow with features designed to make your life easier. Here are some of the core capabilities you'll find:
- Opinionated Azure Resource Management: Simplified APIs for provisioning and managing common Azure resources like Resource Groups, Storage Accounts, App Services, and Kubernetes clusters.
- Container Orchestration Helpers: Utilities for building, tagging, pushing Docker images, and deploying them to various container services (Azure Container Instances, Azure Kubernetes Service).
- CI/CD Pipeline Integration: Seamless integration points for popular CI/CD platforms, making it trivial to incorporate cloud operations into your automated build and deployment processes.
- Configuration Management: Robust handling of secrets and environment-specific configurations, ensuring your deployments are secure and adaptable.
- Extensible Workflow Engine: A pluggable architecture that allows you to define custom steps and integrate with other tools, ensuring Saadati.CloudFlow adapts to your unique needs.
- CLI Tool: A powerful command-line interface for quick scripting and ad-hoc operations, perfect for local development or shell-based automation.
Installation
Getting Saadati.CloudFlow up and running is straightforward. We offer both a NuGet package for your .NET projects and a global command-line tool.
Prerequisites
Before you dive in, make sure you have these essentials:
- .NET SDK 6.0 or higher: This is the bedrock for everything we do here.
- Azure CLI: While not strictly required for all operations, it's highly recommended for authentication and certain advanced scenarios.
- Docker Desktop (or equivalent): If you're planning to work with containers, you'll need a Docker environment.
NuGet Package Installation
For integrating Saadati.CloudFlow into your C# applications, simply add the NuGet package:
dotnet add package Saadati.CloudFlow
Or, if you prefer using the NuGet Package Manager in Visual Studio:
Install-Package Saadati.CloudFlow
Global CLI Tool Installation
To use the cloudflow command-line tool globally on your system, open your terminal and run:
dotnet tool install --global Saadati.CloudFlow.Cli
Once installed, you can verify it by running:
cloudflow --version
You should see the installed version number. If you ever need to update it, just use:
dotnet tool update --global Saadati.CloudFlow.Cli
Usage
Let's dive into some practical examples to show you how Saadati.CloudFlow simplifies common tasks.
Authenticating with Azure
Before you can do anything useful with Azure, you need to authenticate. Saadati.CloudFlow leverages the Azure CLI's authentication mechanisms, so if you're already logged in there, you're good to go. Otherwise, you can log in via the CLI:
az login
The library will pick up your credentials automatically. Easy peasy.
C# API Usage: Provisioning an Azure Storage Account
Here's how you might use the C# API to provision a new Azure Resource Group and a Storage Account within it. Notice how much boilerplate is abstracted away – you define your intent, and CloudFlow handles the details.
using System;
using System.Threading.Tasks;
using Saadati.CloudFlow.Azure;
using Saadati.CloudFlow.Configuration;
using Microsoft.Extensions.Configuration; // For IConfiguration
public class StorageProvisioner
{
private readonly ICloudFlowConfig _config;
private readonly IAzureResourceManager _resourceManager;
public StorageProvisioner(IConfiguration appConfig)
{
// CloudFlow integrates well with Microsoft.Extensions.Configuration
// You'd typically inject ICloudFlowConfig or build it from IConfiguration
_config = new CloudFlowConfig(appConfig.GetSection("CloudFlow"));
_resourceManager = new AzureResourceManager(_config);
}
public async Task CreateStorageAccountAsync(string resourceGroupName, string storageAccountName, string location)
{
Console.WriteLine($"Ensuring Resource Group '{resourceGroupName}' exists in '{location}'...");
var rg = await _resourceManager.EnsureResourceGroupExistsAsync(resourceGroupName, location);
Console.WriteLine($"Resource Group '{rg.Name}' is ready.");
Console.WriteLine($"Creating Storage Account '{storageAccountName}'...");
var storageAccount = await _resourceManager.CreateStorageAccountAsync(
resourceGroupName,
storageAccountName,
location,
StorageSku.Standard_LRS // Example SKU, many options available
);
Console.WriteLine($"Storage Account '{storageAccount.Name}' created with ID: {storageAccount.Id}");
Console.WriteLine("Provisioning complete!");
}
public static async Task Main(string[] args)
{
// Example configuration setup
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
var config = builder.Build();
var provisioner = new StorageProvisioner(config);
// These values would typically come from configuration or parameters
string rgName = Environment.GetEnvironmentVariable("AZURE_RESOURCE_GROUP_NAME") ?? "my-cloudflow-rg";
string saName = Environment.GetEnvironmentVariable("AZURE_STORAGE_ACCOUNT_NAME") ?? $"cloudflowsa{Guid.NewGuid().ToString().Replace("-", "")[..10]}";
string loc = Environment.GetEnvironmentVariable("AZURE_LOCATION") ?? "eastus";
await provisioner.CreateStorageAccountAsync(rgName, saName, loc);
}
}
This code snippet assumes you have some basic appsettings.json or environment variables for configuration. The key takeaway is how IAzureResourceManager simplifies interaction with Azure.
CLI Usage: Deploying a Container Image
The cloudflow CLI is fantastic for scripting and local development. Let's say you've built a Docker image and want to quickly push it to Azure Container Registry (ACR) and then deploy it as an Azure Container Instance (ACI).
First, ensure you're logged into Azure and have an ACR configured.
-
Build and Tag Your Docker Image:
docker build -t myapp:1.0 . -
Login to ACR (if not already):
cloudflow container login --registry myregistry.azurecr.ioThis command simplifies the
az acr loginexperience. -
Tag and Push to ACR:
cloudflow container push --source-tag myapp:1.0 --target-registry myregistry.azurecr.io --target-tag myapp:1.0Behind the scenes, this handles tagging the image for your ACR and then pushing it.
-
Deploy to Azure Container Instance:
cloudflow container deploy aci \ --name myapp-instance \ --resource-group my-cloudflow-rg \ --image myregistry.azurecr.io/myapp:1.0 \ --location eastus \ --cpu 1 \ --memory 1.5 \ --port 80 \ --environment "ASPNETCORE_ENVIRONMENT=Production" "APP_SETTING_SECRET=$(cloudflow secret get MySuperSecret)"Notice the
--environmentflags, demonstrating how you can easily inject environment variables, including retrieving secrets managed by CloudFlow.
Integrating with CI/CD (Example: Azure DevOps Pipeline)
One of my favorite use cases for Saadati.CloudFlow is simplifying CI/CD pipelines. Instead of writing verbose YAML for Azure CLI tasks, you can encapsulate complex logic in a C# script or a few cloudflow CLI commands.
Here's a snippet from an Azure DevOps azure-pipelines.yml that uses the cloudflow CLI:
# azure-pipelines.yml
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
# Define your variables here, or use variable groups
azureResourceManagerConnection: 'MyAzureServiceConnection'
azureSubscriptionId: '$(AZURE_SUBSCRIPTION_ID)' # Link to a variable group or pipeline var
acrRegistryName: 'myregistryname'
imageName: 'mywebapp'
imageTag: '$(Build.BuildId)' # Use the build ID as a unique tag
steps:
- task: UseDotNet@2
displayName: 'Install .NET SDK'
inputs:
version: '6.x'
- script: |
dotnet tool install --global Saadati.CloudFlow.Cli --version 1.0.0 # Pin to a specific version!
displayName: 'Install CloudFlow CLI'
- script: |
# Ensure Azure login is handled by the service connection
# Or, if using workload identity, rely on that.
# For this example, assuming a service connection that provides AZURE_SUBSCRIPTION_ID etc.
echo "Using CloudFlow to deploy application..."
cloudflow container deploy aci \
--name $(imageName)-$(imageTag) \
--resource-group $(yourResourceGroupName) \
--image $(acrRegistryName).azurecr.io/$(imageName):$(imageTag) \
--location eastus \
--cpu 1 \
--memory 1.5 \
--port 80
displayName: 'Deploy App with CloudFlow CLI to ACI'
env:
AZURE_SUBSCRIPTION_ID: $(azureSubscriptionId)
# Potentially other AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET if needed for SPN
This demonstrates how cleanly cloudflow commands fit into existing CI/CD systems, reducing the complexity of your pipeline definitions.
FAQ
Here are some questions I often get about Saadati.CloudFlow.
Q: What clouds does Saadati.CloudFlow support?
A: Primarily, Saadati.CloudFlow is optimized for Azure. My own work and expertise are heavily invested there, and that's where the most comprehensive features reside. However, the underlying principles and abstractions are designed to be cloud-agnostic where possible. We have basic container-related utilities that work regardless of the cloud, and future plans include expanding support for other platforms like AWS and GCP, driven by community contributions and demand.
Q: Is this library opinionated?
A: Absolutely, and intentionally so! My goal was to create a tool that guides developers towards best practices and common patterns, especially in the Azure ecosystem. While it offers flexibility, it also makes certain decisions for you to reduce cognitive load and potential misconfigurations. I believe strong opinions, loosely held, lead to more robust and maintainable systems.
Q: How does Saadati.CloudFlow handle secrets?
A: Security is paramount. Saadati.CloudFlow integrates with established secret management solutions. For Azure, it can fetch secrets directly from Azure Key Vault. For local development or CI/CD, it supports environment variables, and we're exploring integrations with other secret stores. The CLI includes commands like cloudflow secret get <keyName> to retrieve secrets securely.
Q: Can I extend Saadati.CloudFlow with my own custom operations?
A: Yes, definitely! The C# library is designed with extensibility in mind. You can implement your own ICloudFlowStep or IAzureResourceManager extensions. The goal is to provide a solid foundation but allow you to plug in your specific logic when needed. We're actively working on clearer documentation and examples for building custom extensions.
Q: Is Saadati.CloudFlow open source?
A: Yes, it is! I firmly believe in the power of community and transparent development. The project is hosted on GitHub, and I encourage contributions, feedback, and discussions.
Troubleshooting
Even the best tools hit a snag sometimes. Here are a few common issues and how to tackle them.
Problem: Azure Authentication Errors (e.g., "Unauthorized," "Subscription Not Found")
- Symptom: Operations fail with messages indicating permission issues or an inability to find your Azure subscription.
- Likely Cause:
- You're not logged into Azure CLI, or your credentials have expired.
- The service principal/managed identity used by your CI/CD pipeline doesn't have the necessary permissions.
- You're trying to operate in a subscription that your current context doesn't have access to.
- Solution:
- Local Dev: Run `
Top comments (0)