From d5586dae7f8184906ce8fa592fccff0fb6a4fa19 Mon Sep 17 00:00:00 2001 From: sebas_correa Date: Fri, 20 Mar 2026 10:12:08 -0300 Subject: [PATCH] feat(messaging): add Azure Service Bus service module Add new service for Azure Service Bus following the same patterns as azure-cosmos-db. Supports creating queues and topics (with subscriptions) in an existing namespace. Link/unlink workflows grant namespace-level RBAC access (sender, receiver, or owner) to the consuming app's managed identity via azurerm_role_assignment. Co-Authored-By: Claude Sonnet 4.6 --- messaging/azure-service-bus/.gitignore | 15 +++ .../azure-service-bus/deployment/main.tf | 36 +++++++ .../azure-service-bus/deployment/outputs.tf | 29 +++++ .../azure-service-bus/deployment/providers.tf | 13 +++ .../azure-service-bus/deployment/variables.tf | 33 ++++++ .../azure-service-bus/entrypoint/entrypoint | 52 +++++++++ messaging/azure-service-bus/entrypoint/link | 34 ++++++ .../azure-service-bus/entrypoint/service | 28 +++++ .../azure-service-bus/permissions/locals.tf | 8 ++ .../azure-service-bus/permissions/main.tf | 15 +++ .../azure-service-bus/permissions/outputs.tf | 24 +++++ .../permissions/providers.tf | 13 +++ .../permissions/variables.tf | 35 ++++++ .../scripts/azure/build_context | 101 ++++++++++++++++++ .../scripts/azure/build_permissions_context | 61 +++++++++++ .../azure-service-bus/scripts/azure/do_tofu | 19 ++++ .../scripts/azure/generate_resource_name | 71 ++++++++++++ .../scripts/azure/resolve_azure_context | 21 ++++ .../specs/links/connect.json.tpl | 34 ++++++ .../specs/service-spec.json.tpl | 86 +++++++++++++++ messaging/azure-service-bus/values.yaml | 13 +++ .../workflows/azure/create.yaml | 19 ++++ .../workflows/azure/delete.yaml | 19 ++++ .../workflows/azure/link.yaml | 48 +++++++++ .../workflows/azure/unlink.yaml | 9 ++ .../workflows/azure/update.yaml | 19 ++++ 26 files changed, 855 insertions(+) create mode 100644 messaging/azure-service-bus/.gitignore create mode 100644 messaging/azure-service-bus/deployment/main.tf create mode 100644 messaging/azure-service-bus/deployment/outputs.tf create mode 100644 messaging/azure-service-bus/deployment/providers.tf create mode 100644 messaging/azure-service-bus/deployment/variables.tf create mode 100755 messaging/azure-service-bus/entrypoint/entrypoint create mode 100755 messaging/azure-service-bus/entrypoint/link create mode 100755 messaging/azure-service-bus/entrypoint/service create mode 100644 messaging/azure-service-bus/permissions/locals.tf create mode 100644 messaging/azure-service-bus/permissions/main.tf create mode 100644 messaging/azure-service-bus/permissions/outputs.tf create mode 100644 messaging/azure-service-bus/permissions/providers.tf create mode 100644 messaging/azure-service-bus/permissions/variables.tf create mode 100755 messaging/azure-service-bus/scripts/azure/build_context create mode 100755 messaging/azure-service-bus/scripts/azure/build_permissions_context create mode 100755 messaging/azure-service-bus/scripts/azure/do_tofu create mode 100755 messaging/azure-service-bus/scripts/azure/generate_resource_name create mode 100755 messaging/azure-service-bus/scripts/azure/resolve_azure_context create mode 100644 messaging/azure-service-bus/specs/links/connect.json.tpl create mode 100644 messaging/azure-service-bus/specs/service-spec.json.tpl create mode 100644 messaging/azure-service-bus/values.yaml create mode 100644 messaging/azure-service-bus/workflows/azure/create.yaml create mode 100644 messaging/azure-service-bus/workflows/azure/delete.yaml create mode 100644 messaging/azure-service-bus/workflows/azure/link.yaml create mode 100644 messaging/azure-service-bus/workflows/azure/unlink.yaml create mode 100644 messaging/azure-service-bus/workflows/azure/update.yaml diff --git a/messaging/azure-service-bus/.gitignore b/messaging/azure-service-bus/.gitignore new file mode 100644 index 0000000..7d0a1ba --- /dev/null +++ b/messaging/azure-service-bus/.gitignore @@ -0,0 +1,15 @@ +# Terraform +.terraform/ +*.tfstate +*.tfstate.backup +.terraform.lock.hcl +*.tfvars +*.auto.tfvars +*.tfvars.json + +# Dynamically generated backend config +deployment/backend.tf +permissions/backend.tf + +# Build output directory +output/ diff --git a/messaging/azure-service-bus/deployment/main.tf b/messaging/azure-service-bus/deployment/main.tf new file mode 100644 index 0000000..8ff7cd9 --- /dev/null +++ b/messaging/azure-service-bus/deployment/main.tf @@ -0,0 +1,36 @@ +data "azurerm_servicebus_namespace" "existing" { + name = var.servicebus_namespace_name + resource_group_name = var.resource_group_name +} + +resource "azurerm_servicebus_queue" "queues" { + for_each = { for q in var.queues : q.name => q } + + name = each.value.name + namespace_id = data.azurerm_servicebus_namespace.existing.id +} + +resource "azurerm_servicebus_topic" "topics" { + for_each = { for t in var.topics : t.name => t } + + name = each.value.name + namespace_id = data.azurerm_servicebus_namespace.existing.id +} + +resource "azurerm_servicebus_subscription" "subscriptions" { + for_each = { + for item in flatten([ + for t in var.topics : [ + for s in t.subscriptions : { + key = "${t.name}--${s.name}" + topic_name = t.name + sub_name = s.name + } + ] + ]) : item.key => item + } + + name = each.value.sub_name + topic_id = azurerm_servicebus_topic.topics[each.value.topic_name].id + max_delivery_count = 10 +} diff --git a/messaging/azure-service-bus/deployment/outputs.tf b/messaging/azure-service-bus/deployment/outputs.tf new file mode 100644 index 0000000..9b5f567 --- /dev/null +++ b/messaging/azure-service-bus/deployment/outputs.tf @@ -0,0 +1,29 @@ +output "namespace_name" { + description = "Service Bus namespace name" + value = data.azurerm_servicebus_namespace.existing.name +} + +output "namespace_id" { + description = "Service Bus namespace resource ID" + value = data.azurerm_servicebus_namespace.existing.id +} + +output "queues" { + description = "Created queues" + value = [ + for name, queue in azurerm_servicebus_queue.queues : { + name = name + id = queue.id + } + ] +} + +output "topics" { + description = "Created topics with their subscriptions" + value = [ + for name, topic in azurerm_servicebus_topic.topics : { + name = name + id = topic.id + } + ] +} diff --git a/messaging/azure-service-bus/deployment/providers.tf b/messaging/azure-service-bus/deployment/providers.tf new file mode 100644 index 0000000..3f2ce26 --- /dev/null +++ b/messaging/azure-service-bus/deployment/providers.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + +provider "azurerm" { + features {} + subscription_id = var.subscription_id +} diff --git a/messaging/azure-service-bus/deployment/variables.tf b/messaging/azure-service-bus/deployment/variables.tf new file mode 100644 index 0000000..30e3274 --- /dev/null +++ b/messaging/azure-service-bus/deployment/variables.tf @@ -0,0 +1,33 @@ +variable "subscription_id" { + description = "Azure subscription ID" + type = string +} + +variable "resource_group_name" { + description = "Resource group where the Service Bus namespace exists" + type = string +} + +variable "servicebus_namespace_name" { + description = "Existing Service Bus namespace name" + type = string +} + +variable "queues" { + description = "List of queues to create in the namespace" + type = list(object({ + name = string + })) + default = [] +} + +variable "topics" { + description = "List of topics to create with their subscriptions" + type = list(object({ + name = string + subscriptions = list(object({ + name = string + })) + })) + default = [] +} diff --git a/messaging/azure-service-bus/entrypoint/entrypoint b/messaging/azure-service-bus/entrypoint/entrypoint new file mode 100755 index 0000000..27118f5 --- /dev/null +++ b/messaging/azure-service-bus/entrypoint/entrypoint @@ -0,0 +1,52 @@ +#!/bin/bash +set -euo pipefail + +if [ -z "${NP_ACTION_CONTEXT:-}" ]; then + echo "NP_ACTION_CONTEXT is not set. Exiting." + exit 1 +fi + +CLEAN_CONTEXT=$(echo "$NP_ACTION_CONTEXT" | sed "s/^'//;s/'$//") +export NP_ACTION_CONTEXT="$CLEAN_CONTEXT" + +export CONTEXT=$(echo "$CLEAN_CONTEXT" | jq '.notification') +export SERVICE_ACTION=$(echo "$CONTEXT" | jq -r '.slug') +export SERVICE_ACTION_TYPE=$(echo "$CONTEXT" | jq -r '.type') +export NOTIFICATION_ACTION=$(echo "$CONTEXT" | jq -r '.action') +export LINK=$(echo "$CONTEXT" | jq '.link') + +ACTION_SOURCE=service +IS_LINK_ACTION=$(echo "$CONTEXT" | jq '.link != null') + +if [ "$IS_LINK_ACTION" = "true" ]; then + ACTION_SOURCE=link +fi + +export WORKING_DIRECTORY="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +SERVICE_PATH="" +OVERRIDES_PATH="" + +for arg in "$@"; do + case $arg in + --service-path=*) + SERVICE_PATH="${arg#*=}" + ;; + --overrides-path=*) + OVERRIDES_PATH="${arg#*=}" + ;; + *) + echo "Unknown argument: $arg" + exit 1 + ;; + esac +done + +SERVICE_PATH="${SERVICE_PATH:-$(dirname "$WORKING_DIRECTORY")}" +OVERRIDES_PATH="${OVERRIDES_PATH:-$SERVICE_PATH/overrides}" + +export SERVICE_PATH +export OVERRIDES_PATH +export ACTION_SOURCE + +np service-action exec --live-output --live-report --script="$WORKING_DIRECTORY/$ACTION_SOURCE" diff --git a/messaging/azure-service-bus/entrypoint/link b/messaging/azure-service-bus/entrypoint/link new file mode 100755 index 0000000..8e31e8c --- /dev/null +++ b/messaging/azure-service-bus/entrypoint/link @@ -0,0 +1,34 @@ +#!/bin/bash + +echo "Executing link action=$SERVICE_ACTION type=$SERVICE_ACTION_TYPE" + +ACTION_TO_EXECUTE="$SERVICE_ACTION_TYPE" + +case "$SERVICE_ACTION_TYPE" in + "custom") + ACTION_TO_EXECUTE="$SERVICE_ACTION" + ;; + "create") + ACTION_TO_EXECUTE="link" + ;; + "delete") + ACTION_TO_EXECUTE="unlink" + ;; +esac + +WORKFLOW_PATH="$SERVICE_PATH/workflows/azure/$ACTION_TO_EXECUTE.yaml" +OVERRIDES_WORKFLOW_PATH="$OVERRIDES_PATH/workflows/azure/$ACTION_TO_EXECUTE.yaml" +VALUES_PATH="$SERVICE_PATH/values.yaml" + +CMD="np service workflow exec --workflow $WORKFLOW_PATH" + +if [[ -f "$VALUES_PATH" ]]; then + CMD="$CMD --values $VALUES_PATH" +fi + +if [[ -f "$OVERRIDES_WORKFLOW_PATH" ]]; then + CMD="$CMD --overrides $OVERRIDES_WORKFLOW_PATH" +fi + +echo "Executing command: $CMD" +eval "$CMD" diff --git a/messaging/azure-service-bus/entrypoint/service b/messaging/azure-service-bus/entrypoint/service new file mode 100755 index 0000000..d7800cb --- /dev/null +++ b/messaging/azure-service-bus/entrypoint/service @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Executing service action=$SERVICE_ACTION type=$SERVICE_ACTION_TYPE" + +ACTION_TO_EXECUTE="$SERVICE_ACTION_TYPE" + +case "$SERVICE_ACTION_TYPE" in + "custom") + ACTION_TO_EXECUTE="$SERVICE_ACTION" + ;; +esac + +WORKFLOW_PATH="$SERVICE_PATH/workflows/azure/$ACTION_TO_EXECUTE.yaml" +OVERRIDES_WORKFLOW_PATH="$OVERRIDES_PATH/workflows/azure/$ACTION_TO_EXECUTE.yaml" +VALUES_PATH="$SERVICE_PATH/values.yaml" + +CMD="np service workflow exec --workflow $WORKFLOW_PATH" + +if [[ -f "$VALUES_PATH" ]]; then + CMD="$CMD --values $VALUES_PATH" +fi + +if [[ -f "$OVERRIDES_WORKFLOW_PATH" ]]; then + CMD="$CMD --overrides $OVERRIDES_WORKFLOW_PATH" +fi + +echo "Executing command: $CMD" +eval "$CMD" diff --git a/messaging/azure-service-bus/permissions/locals.tf b/messaging/azure-service-bus/permissions/locals.tf new file mode 100644 index 0000000..45e55ec --- /dev/null +++ b/messaging/azure-service-bus/permissions/locals.tf @@ -0,0 +1,8 @@ +locals { + # Azure built-in role names for Service Bus + role_names = { + sender = "Azure Service Bus Data Sender" + receiver = "Azure Service Bus Data Receiver" + owner = "Azure Service Bus Data Owner" + } +} diff --git a/messaging/azure-service-bus/permissions/main.tf b/messaging/azure-service-bus/permissions/main.tf new file mode 100644 index 0000000..4de7f85 --- /dev/null +++ b/messaging/azure-service-bus/permissions/main.tf @@ -0,0 +1,15 @@ +data "azurerm_servicebus_namespace" "existing" { + name = var.servicebus_namespace_name + resource_group_name = var.resource_group_name +} + +data "azurerm_linux_web_app" "app" { + name = var.app_name + resource_group_name = var.app_resource_group +} + +resource "azurerm_role_assignment" "servicebus_access" { + scope = data.azurerm_servicebus_namespace.existing.id + role_definition_name = local.role_names[var.access_level] + principal_id = data.azurerm_linux_web_app.app.identity[0].principal_id +} diff --git a/messaging/azure-service-bus/permissions/outputs.tf b/messaging/azure-service-bus/permissions/outputs.tf new file mode 100644 index 0000000..86aa4a8 --- /dev/null +++ b/messaging/azure-service-bus/permissions/outputs.tf @@ -0,0 +1,24 @@ +output "namespace_id" { + description = "Service Bus namespace resource ID" + value = data.azurerm_servicebus_namespace.existing.id +} + +output "namespace_name" { + description = "Service Bus namespace name" + value = data.azurerm_servicebus_namespace.existing.name +} + +output "app_principal_id" { + description = "The principal ID of the app's managed identity" + value = data.azurerm_linux_web_app.app.identity[0].principal_id +} + +output "role_assignment_id" { + description = "Role assignment resource ID" + value = azurerm_role_assignment.servicebus_access.id +} + +output "access_level" { + description = "Granted access level" + value = var.access_level +} diff --git a/messaging/azure-service-bus/permissions/providers.tf b/messaging/azure-service-bus/permissions/providers.tf new file mode 100644 index 0000000..3f2ce26 --- /dev/null +++ b/messaging/azure-service-bus/permissions/providers.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + +provider "azurerm" { + features {} + subscription_id = var.subscription_id +} diff --git a/messaging/azure-service-bus/permissions/variables.tf b/messaging/azure-service-bus/permissions/variables.tf new file mode 100644 index 0000000..5adcca0 --- /dev/null +++ b/messaging/azure-service-bus/permissions/variables.tf @@ -0,0 +1,35 @@ +variable "subscription_id" { + description = "Azure subscription ID" + type = string +} + +variable "resource_group_name" { + description = "Resource group where the Service Bus namespace exists" + type = string +} + +variable "servicebus_namespace_name" { + description = "Service Bus namespace name" + type = string +} + +variable "app_name" { + description = "Azure App Service name (the NP scope consuming this service)" + type = string +} + +variable "app_resource_group" { + description = "Resource group where the Azure App Service lives" + type = string +} + +variable "access_level" { + description = "Access level to grant: sender, receiver, or owner" + type = string + default = "receiver" + + validation { + condition = contains(["sender", "receiver", "owner"], var.access_level) + error_message = "access_level must be one of: sender, receiver, owner." + } +} diff --git a/messaging/azure-service-bus/scripts/azure/build_context b/messaging/azure-service-bus/scripts/azure/build_context new file mode 100755 index 0000000..44321db --- /dev/null +++ b/messaging/azure-service-bus/scripts/azure/build_context @@ -0,0 +1,101 @@ +#!/bin/bash + +set -euo pipefail + +SERVICE_ID=$(echo "$CONTEXT" | jq -r .service.id) +SERVICE_SLUG=$(echo "$CONTEXT" | jq -r .service.slug) + +ACTION_ID=$(echo "$CONTEXT" | jq -r .id) +ACTION_NAME=$(echo "$CONTEXT" | jq -r .slug) + +# Link context (when action comes from a link) +LINK_ID=$(echo "$CONTEXT" | jq -r '.link.id // ""') +LINK_NAME=$(echo "$CONTEXT" | jq -r '.link.slug // ""') +SCOPE_ID=$(echo "$CONTEXT" | jq -r '.tags.scope_id // ""') +SCOPE_NRN=$(echo "$CONTEXT" | jq -r '.tags.nrn // ""') + +# Link parameters +LINK_ACCESS_LEVEL=$(echo "$CONTEXT" | jq -r '.parameters.access_level // .link.attributes.access_level // "receiver"') + +# Read static configuration from values.yaml +VALUES_FILE="$SERVICE_PATH/values.yaml" + +if [ -f "$VALUES_FILE" ]; then + NAMESPACE_RESOURCE_GROUP=$(yq -r '.resource_group_name // ""' "$VALUES_FILE") + NAMESPACE_NAME=$(yq -r '.servicebus_namespace_name // ""' "$VALUES_FILE") + APP_RESOURCE_GROUP=$(yq -r '.app_resource_group // ""' "$VALUES_FILE") +else + echo "WARNING: values.yaml not found at $VALUES_FILE" + NAMESPACE_RESOURCE_GROUP="" + NAMESPACE_NAME="" + APP_RESOURCE_GROUP="" +fi + +# Azure subscription ID from environment +SUBSCRIPTION_ID="$AZURE_SUBSCRIPTION_ID" + +# Parse queues array from service parameters +QUEUES=$(echo "$CONTEXT" | jq -c '[.parameters.queues // [] | .[] | {name: .name}]') + +# Parse topics array from service parameters (including subscriptions) +TOPICS=$(echo "$CONTEXT" | jq -c '[.parameters.topics // [] | .[] | { + name: .name, + subscriptions: [.subscriptions // [] | .[] | {name: .name}] +}]') + +OUTPUT_DIR="$SERVICE_PATH/output/$SERVICE_SLUG-$SERVICE_ID/$ACTION_NAME-$ACTION_ID" +mkdir -p "$OUTPUT_DIR" + +TOFU_MODULE_DIR="$SERVICE_PATH/deployment" + +# Backend config for tfstate +if [ -n "${AZURE_TFSTATE_STORAGE_ACCOUNT:-}" ] && [ -n "${AZURE_TFSTATE_CONTAINER:-}" ]; then + echo "Using Azure backend for tfstate" + + TFSTATE_RESOURCE_GROUP="${AZURE_TFSTATE_RESOURCE_GROUP:-$NAMESPACE_RESOURCE_GROUP}" + TFSTATE_KEY="service-bus/${SERVICE_ID}/infrastructure.tfstate" + + cat > "$TOFU_MODULE_DIR/backend.tf" < "$TOFU_MODULE_DIR/backend.tf" < "$TOFU_VAR_FILE" + +tofu -chdir="$TOFU_MODULE_DIR" init -input=false $TOFU_INIT_VARIABLES + +tofu -chdir="$TOFU_MODULE_DIR" "$TOFU_ACTION" -auto-approve -var-file="$TOFU_VAR_FILE" + +if [ "$TOFU_ACTION" = "apply" ]; then + RESULTS=$(tofu -chdir="$TOFU_MODULE_DIR" output -json | jq 'map_values(.value)') + + np "$ACTION_SOURCE" action update --results "$RESULTS" --status "success" +fi diff --git a/messaging/azure-service-bus/scripts/azure/generate_resource_name b/messaging/azure-service-bus/scripts/azure/generate_resource_name new file mode 100755 index 0000000..65d4e55 --- /dev/null +++ b/messaging/azure-service-bus/scripts/azure/generate_resource_name @@ -0,0 +1,71 @@ +#!/bin/bash +# ============================================================================= +# Generate Resource Name +# +# Generates a resource name from segments with intelligent truncation. +# The ID (last segment) is always preserved; if the name exceeds max length, +# full segments are removed from the left until it fits. +# +# Usage: +# ./generate_resource_name ... +# +# Example: +# ./generate_resource_name 60 "$NAMESPACE_SLUG" "$APPLICATION_SLUG" "$SCOPE_SLUG" "$SCOPE_ID" +# # Output: namespace-application-scope-123 +# # Or if too long: application-scope-123 (removes leftmost segments first) +# +# Arguments: +# max_length Maximum allowed length for the final name +# segments One or more name segments (last one is the ID, always preserved) +# +# Output: +# Prints the generated name to stdout +# ============================================================================= + +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "Usage: $0 [segment2] ... " >&2 + echo "Example: $0 60 namespace app scope 123" >&2 + exit 1 +fi + +max_length="$1" +shift + +segments=("$@") +segment_count=${#segments[@]} + +id="${segments[$((segment_count - 1))]}" +suffix="-${id}" +suffix_length=${#suffix} +max_prefix_length=$((max_length - suffix_length)) + +prefix="" +for ((i = 0; i < segment_count - 1; i++)); do + if [ -n "$prefix" ]; then + prefix="${prefix}-${segments[$i]}" + else + prefix="${segments[$i]}" + fi +done + +if [ -z "$prefix" ]; then + echo "$id" + exit 0 +fi + +while [ ${#prefix} -gt $max_prefix_length ]; do + if [[ "$prefix" == *-* ]]; then + prefix="${prefix#*-}" + else + prefix="${prefix:0:$max_prefix_length}" + break + fi +done + +if [ -z "$prefix" ]; then + echo "$id" +else + echo "${prefix}${suffix}" +fi diff --git a/messaging/azure-service-bus/scripts/azure/resolve_azure_context b/messaging/azure-service-bus/scripts/azure/resolve_azure_context new file mode 100755 index 0000000..3e86658 --- /dev/null +++ b/messaging/azure-service-bus/scripts/azure/resolve_azure_context @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +SCOPE_ID=$(echo "$CONTEXT" | jq -r .tags.scope_id) +SCOPE_SLUG=$(echo "$CONTEXT" | jq -r .tags.scope) +NS_SLUG=$(echo "$CONTEXT" | jq -r .tags.namespace) +APP_SLUG=$(echo "$CONTEXT" | jq -r .tags.application) + +if [ -z "${SCOPE_ID:-}" ]; then + echo "Error: Missing required parameter: scope_id" >&2 + exit 1 +fi + +if [ -z "${SCOPE_SLUG:-}" ] || [ -z "${NS_SLUG:-}" ] || [ -z "${APP_SLUG:-}" ]; then + echo "Error: Could not extract slugs from context" >&2 + exit 1 +fi + +RESOURCE_NAME_MAX_LENGTH=60 +APP_NAME=$("$SERVICE_PATH/scripts/azure/generate_resource_name" "$RESOURCE_NAME_MAX_LENGTH" "$NS_SLUG" "$APP_SLUG" "$SCOPE_SLUG" "$SCOPE_ID") +export APP_NAME diff --git a/messaging/azure-service-bus/specs/links/connect.json.tpl b/messaging/azure-service-bus/specs/links/connect.json.tpl new file mode 100644 index 0000000..c8d14c5 --- /dev/null +++ b/messaging/azure-service-bus/specs/links/connect.json.tpl @@ -0,0 +1,34 @@ +{ + "id": "f4b2e8d3-0c5a-4f9e-b3d7-4e5f6a7b8c9d", + "name": "Connect", + "slug": "connect", + "visible_to": [], + "dimensions": {}, + "scopes": {}, + "assignable_to": "any", + "use_default_actions": true, + "selectors": { + "category": "Messaging", + "imported": false, + "provider": "Azure", + "sub_category": "Message Bus" + }, + "attributes": { + "schema": { + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "required": ["access_level"], + "properties": { + "access_level": { + "type": "string", + "title": "Access Level", + "description": "Permission level granted to the application on this Service Bus namespace", + "enum": ["sender", "receiver", "owner"], + "default": "receiver", + "editableOn": ["create", "update"] + } + } + }, + "values": {} + } +} diff --git a/messaging/azure-service-bus/specs/service-spec.json.tpl b/messaging/azure-service-bus/specs/service-spec.json.tpl new file mode 100644 index 0000000..c4b30cc --- /dev/null +++ b/messaging/azure-service-bus/specs/service-spec.json.tpl @@ -0,0 +1,86 @@ +{ + "id": "e3a1f7c2-9b4d-4e8f-a2c6-3d5e6f7a8b9c", + "name": "Azure Service Bus", + "slug": "azure-service-bus", + "type": "dependency", + "visible_to": [], + "dimensions": {}, + "scopes": {}, + "assignable_to": "any", + "use_default_actions": true, + "available_actions": [], + "available_links": ["connect"], + "selectors": { + "category": "Messaging", + "imported": false, + "provider": "Azure", + "sub_category": "Message Bus" + }, + "attributes": { + "schema": { + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "required": [], + "properties": { + "queues": { + "type": "array", + "title": "Queues", + "description": "List of queues to create in the Service Bus namespace", + "editableOn": ["create", "update"], + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "order": 1, + "title": "Queue Name", + "description": "Name of the queue", + "editableOn": ["create"] + } + } + } + }, + "topics": { + "type": "array", + "title": "Topics", + "description": "List of topics to create in the Service Bus namespace", + "editableOn": ["create", "update"], + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "order": 1, + "title": "Topic Name", + "description": "Name of the topic", + "editableOn": ["create"] + }, + "subscriptions": { + "type": "array", + "order": 2, + "title": "Subscriptions", + "description": "List of subscriptions for this topic", + "editableOn": ["create", "update"], + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "title": "Subscription Name", + "description": "Name of the subscription", + "editableOn": ["create"] + } + } + } + } + } + } + } + } + }, + "values": {} + } +} diff --git a/messaging/azure-service-bus/values.yaml b/messaging/azure-service-bus/values.yaml new file mode 100644 index 0000000..a01bd29 --- /dev/null +++ b/messaging/azure-service-bus/values.yaml @@ -0,0 +1,13 @@ +# Azure Service Bus Service — Static Configuration +# These values are not exposed in the NP UI. They configure the execution +# environment for the agent running this service. + +# Resource group where the Service Bus namespace lives +resource_group_name: "rg-nullplatform-demos-shared" + +# Name of the existing Service Bus namespace +servicebus_namespace_name: "np-servicebus" + +# Resource group where the Azure App Services (scopes) live +# Used during link/unlink to look up the app's managed identity +app_resource_group: "rg-azureimplementations-poc" diff --git a/messaging/azure-service-bus/workflows/azure/create.yaml b/messaging/azure-service-bus/workflows/azure/create.yaml new file mode 100644 index 0000000..6ca5552 --- /dev/null +++ b/messaging/azure-service-bus/workflows/azure/create.yaml @@ -0,0 +1,19 @@ +steps: + - name: build context + type: script + file: $SERVICE_PATH/scripts/azure/build_context + output: + - name: OUTPUT_DIR + type: environment + - name: TOFU_MODULE_DIR + type: environment + - name: TOFU_INIT_VARIABLES + type: environment + - name: TOFU_VARIABLES + type: environment + + - name: tofu + type: script + file: $SERVICE_PATH/scripts/azure/do_tofu + configuration: + TOFU_ACTION: apply diff --git a/messaging/azure-service-bus/workflows/azure/delete.yaml b/messaging/azure-service-bus/workflows/azure/delete.yaml new file mode 100644 index 0000000..1d645e8 --- /dev/null +++ b/messaging/azure-service-bus/workflows/azure/delete.yaml @@ -0,0 +1,19 @@ +steps: + - name: build context + type: script + file: $SERVICE_PATH/scripts/azure/build_context + output: + - name: OUTPUT_DIR + type: environment + - name: TOFU_MODULE_DIR + type: environment + - name: TOFU_INIT_VARIABLES + type: environment + - name: TOFU_VARIABLES + type: environment + + - name: tofu + type: script + file: $SERVICE_PATH/scripts/azure/do_tofu + configuration: + TOFU_ACTION: destroy diff --git a/messaging/azure-service-bus/workflows/azure/link.yaml b/messaging/azure-service-bus/workflows/azure/link.yaml new file mode 100644 index 0000000..53c3f1d --- /dev/null +++ b/messaging/azure-service-bus/workflows/azure/link.yaml @@ -0,0 +1,48 @@ +steps: + - name: build context + type: script + file: $SERVICE_PATH/scripts/azure/build_context + output: + - name: OUTPUT_DIR + type: environment + - name: LINK_ID + type: environment + - name: LINK_NAME + type: environment + - name: SCOPE_ID + type: environment + - name: SCOPE_NRN + type: environment + - name: LINK_ACCESS_LEVEL + type: environment + - name: SUBSCRIPTION_ID + type: environment + - name: NAMESPACE_RESOURCE_GROUP + type: environment + - name: NAMESPACE_NAME + type: environment + - name: APP_RESOURCE_GROUP + type: environment + + - name: build app name + type: script + file: $SERVICE_PATH/scripts/azure/resolve_azure_context + + - name: build permissions context + type: script + file: $SERVICE_PATH/scripts/azure/build_permissions_context + output: + - name: OUTPUT_DIR + type: environment + - name: TOFU_MODULE_DIR + type: environment + - name: TOFU_INIT_VARIABLES + type: environment + - name: TOFU_VARIABLES + type: environment + + - name: tofu + type: script + file: $SERVICE_PATH/scripts/azure/do_tofu + configuration: + TOFU_ACTION: apply diff --git a/messaging/azure-service-bus/workflows/azure/unlink.yaml b/messaging/azure-service-bus/workflows/azure/unlink.yaml new file mode 100644 index 0000000..5177fdc --- /dev/null +++ b/messaging/azure-service-bus/workflows/azure/unlink.yaml @@ -0,0 +1,9 @@ +include: + - "$SERVICE_PATH/workflows/azure/link.yaml" +steps: + - name: tofu + type: script + file: $SERVICE_PATH/scripts/azure/do_tofu + action: replace + configuration: + TOFU_ACTION: destroy diff --git a/messaging/azure-service-bus/workflows/azure/update.yaml b/messaging/azure-service-bus/workflows/azure/update.yaml new file mode 100644 index 0000000..6ca5552 --- /dev/null +++ b/messaging/azure-service-bus/workflows/azure/update.yaml @@ -0,0 +1,19 @@ +steps: + - name: build context + type: script + file: $SERVICE_PATH/scripts/azure/build_context + output: + - name: OUTPUT_DIR + type: environment + - name: TOFU_MODULE_DIR + type: environment + - name: TOFU_INIT_VARIABLES + type: environment + - name: TOFU_VARIABLES + type: environment + + - name: tofu + type: script + file: $SERVICE_PATH/scripts/azure/do_tofu + configuration: + TOFU_ACTION: apply