Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compose: service bus and event hubs #4743

Merged
merged 10 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/cspell-schemas.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
eventhubs
postdeploy
postdown
postinfracreate
Expand All @@ -12,3 +13,4 @@ preinfradelete
preprovision
prerestore
preup
servicebus
1 change: 1 addition & 0 deletions cli/azd/.vscode/cspell-azd-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ envsubst
errcheck
errorinfo
errorlint
eventhubs
executil
flexconsumption
Frontends
Expand Down
4 changes: 4 additions & 0 deletions cli/azd/internal/cmd/add/add_configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func Configure(
case project.ResourceTypeDbPostgres,
project.ResourceTypeDbMongo:
return fillDatabaseName(ctx, r, console, p)
case project.ResourceTypeMessagingEventHubs:
return fillEventHubs(ctx, r, console, p)
case project.ResourceTypeMessagingServiceBus:
return fillServiceBus(ctx, r, console, p)
case project.ResourceTypeDbRedis:
if _, exists := p.PrjConfig.Resources["redis"]; exists {
return nil, fmt.Errorf("only one Redis resource is allowed at this time")
Expand Down
84 changes: 84 additions & 0 deletions cli/azd/internal/cmd/add/add_configure_messaging.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package add

import (
"context"
"fmt"

"github.com/azure/azure-dev/cli/azd/internal/names"
"github.com/azure/azure-dev/cli/azd/pkg/input"
"github.com/azure/azure-dev/cli/azd/pkg/project"
)

func fillEventHubs(
ctx context.Context,
r *project.ResourceConfig,
console input.Console,
p PromptOptions) (*project.ResourceConfig, error) {
r.Name = "event-hubs"

if _, exists := p.PrjConfig.Resources["event-hubs"]; exists {
return nil, fmt.Errorf("only one event hubs resource is allowed at this time")
}

for {
topicName, err := console.Prompt(ctx, input.ConsoleOptions{
Message: "Input the event hub name:",
Help: "Event hub name\n\n" +
"Name of the event hub that the app connects to. " +
"Also known as a Kafka topic.",
})
if err != nil {
return r, err
}

if err := names.ValidateLabelName(topicName); err != nil {
console.Message(ctx, err.Error())
continue
}

r.Props = project.EventHubsProps{
Hubs: []string{topicName},
}
break
}

return r, nil
}

func fillServiceBus(
ctx context.Context,
r *project.ResourceConfig,
console input.Console,
p PromptOptions) (*project.ResourceConfig, error) {
r.Name = "service-bus"

if _, exists := p.PrjConfig.Resources["service-bus"]; exists {
return nil, fmt.Errorf("only one service bus resource is allowed at this time")
}

for {
queueName, err := console.Prompt(ctx, input.ConsoleOptions{
Message: "Input the queue name:",
Help: "Service Bus queue name\n\n" +
"Name of the queue that the app connects to. ",
})
if err != nil {
return r, err
}

if err := names.ValidateLabelName(queueName); err != nil {
console.Message(ctx, err.Error())
continue
}

r.Props = project.ServiceBusProps{
Queues: []string{queueName},
}
break
}

return r, nil
}
6 changes: 2 additions & 4 deletions cli/azd/internal/cmd/add/add_configure_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@ func fillStorageDetails(
r *project.ResourceConfig,
console input.Console,
p PromptOptions) (*project.ResourceConfig, error) {
r.Name = "storage"

if _, exists := p.PrjConfig.Resources["storage"]; exists {
return nil, fmt.Errorf("only one Storage resource is allowed at this time")
}

if r.Name == "" {
r.Name = "storage"
}

modelProps, ok := r.Props.(project.StorageProps)
if !ok {
return nil, fmt.Errorf("invalid resource properties")
Expand Down
12 changes: 12 additions & 0 deletions cli/azd/internal/cmd/add/add_preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ func Metadata(r *project.ResourceConfig) resourceMeta {
res.UseEnvVars = []string{
"AZURE_OPENAI_ENDPOINT",
}
case project.ResourceTypeMessagingEventHubs:
res.AzureResourceType = "Microsoft.EventHub/namespaces"
res.UseEnvVars = []string{
"AZURE_EVENT_HUBS_HOST",
"AZURE_EVENT_HUBS_NAME",
}
case project.ResourceTypeMessagingServiceBus:
res.AzureResourceType = "Microsoft.ServiceBus/namespaces"
res.UseEnvVars = []string{
"AZURE_SERVICE_BUS_HOST",
"AZURE_SERVICE_BUS_NAME",
}
case project.ResourceTypeStorage:
res.AzureResourceType = "Microsoft.Storage/storageAccounts"
res.UseEnvVars = []string{
Expand Down
26 changes: 26 additions & 0 deletions cli/azd/internal/cmd/add/add_select.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (a *AddAction) selectMenu() []Menu {
{Namespace: "db", Label: "Database", SelectResource: selectDatabase},
{Namespace: "host", Label: "Host service"},
{Namespace: "ai.openai", Label: "Azure OpenAI", SelectResource: a.selectOpenAi},
{Namespace: "messaging", Label: "Messaging", SelectResource: selectMessaging},
{Namespace: "storage", Label: "Storage account", SelectResource: selectStorage},
}
}
Expand Down Expand Up @@ -61,6 +62,31 @@ func selectDatabase(
return r, nil
}

func selectMessaging(
console input.Console,
ctx context.Context,
p PromptOptions) (*project.ResourceConfig, error) {
resourceTypesDisplayMap := make(map[string]project.ResourceType)
for _, resourceType := range project.AllResourceTypes() {
if strings.HasPrefix(string(resourceType), "messaging.") {
resourceTypesDisplayMap[resourceType.String()] = resourceType
}
}

r := &project.ResourceConfig{}
resourceTypesDisplay := slices.Sorted(maps.Keys(resourceTypesDisplayMap))
dbOption, err := console.Select(ctx, input.ConsoleOptions{
Message: "Which type of messaging service?",
Options: resourceTypesDisplay,
})
if err != nil {
return nil, err
}

r.Type = resourceTypesDisplayMap[resourceTypesDisplay[dbOption]]
return r, nil
}

func selectStorage(
console input.Console,
ctx context.Context,
Expand Down
4 changes: 4 additions & 0 deletions cli/azd/internal/scaffold/scaffold_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ func TestExecInfra(t *testing.T) {
DatabaseName: "appdb",
},
DbRedis: &DatabaseRedis{},
ServiceBus: &ServiceBus{},
EventHubs: &EventHubs{},
StorageAccount: &StorageAccount{},
Services: []ServiceSpec{
{
Expand All @@ -111,6 +113,8 @@ func TestExecInfra(t *testing.T) {
DbPostgres: &DatabaseReference{
DatabaseName: "appdb",
},
ServiceBus: &ServiceBus{},
EventHubs: &EventHubs{},
StorageAccount: &StorageReference{},
},
{
Expand Down
18 changes: 18 additions & 0 deletions cli/azd/internal/scaffold/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ type InfraSpec struct {
DbCosmosMongo *DatabaseCosmosMongo
DbRedis *DatabaseRedis

// Messaging services
ServiceBus *ServiceBus
EventHubs *EventHubs

// Storage account
StorageAccount *StorageAccount

// ai models
Expand Down Expand Up @@ -56,6 +61,15 @@ type AIModelModel struct {
Version string
}

type ServiceBus struct {
Queues []string
Topics []string
}

type EventHubs struct {
Hubs []string
}

type StorageAccount struct {
Containers []string
}
Expand All @@ -81,6 +95,10 @@ type ServiceSpec struct {

// AI model connections
AIModels []AIModelReference

// Messaging services
ServiceBus *ServiceBus
EventHubs *EventHubs
}

type Frontend struct {
Expand Down
3 changes: 3 additions & 0 deletions cli/azd/pkg/azapi/azure_resource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
AzureResourceTypeCacheForRedis AzureResourceType = "Microsoft.Cache/redis"
AzureResourceTypeCDNProfile AzureResourceType = "Microsoft.Cdn/profiles"
AzureResourceTypeCosmosDb AzureResourceType = "Microsoft.DocumentDB/databaseAccounts"
AzureResourceTypeEventHubsNamespace AzureResourceType = "Microsoft.EventHub/namespaces"
AzureResourceTypeContainerApp AzureResourceType = "Microsoft.App/containerApps"
AzureResourceTypeSpringApp AzureResourceType = "Microsoft.AppPlatform/Spring"
AzureResourceTypeContainerAppEnvironment AzureResourceType = "Microsoft.App/managedEnvironments"
Expand Down Expand Up @@ -79,6 +80,8 @@ func GetResourceTypeDisplayName(resourceType AzureResourceType) string {
return "Container Apps Environment"
case AzureResourceTypeServiceBusNamespace:
return "Service Bus Namespace"
case AzureResourceTypeEventHubsNamespace:
return "Event Hubs Namespace"
case AzureResourceTypeServicePlan:
return "App Service plan"
case AzureResourceTypeCosmosDb:
Expand Down
65 changes: 47 additions & 18 deletions cli/azd/pkg/project/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@ func AllResourceTypes() []ResourceType {
ResourceTypeDbMongo,
ResourceTypeHostContainerApp,
ResourceTypeOpenAiModel,
ResourceTypeMessagingEventHubs,
ResourceTypeMessagingServiceBus,
ResourceTypeStorage,
}
}

const (
ResourceTypeDbRedis ResourceType = "db.redis"
ResourceTypeDbPostgres ResourceType = "db.postgres"
ResourceTypeDbMongo ResourceType = "db.mongo"
ResourceTypeHostContainerApp ResourceType = "host.containerapp"
ResourceTypeOpenAiModel ResourceType = "ai.openai.model"
ResourceTypeStorage ResourceType = "storage"
ResourceTypeDbRedis ResourceType = "db.redis"
ResourceTypeDbPostgres ResourceType = "db.postgres"
ResourceTypeDbMongo ResourceType = "db.mongo"
ResourceTypeHostContainerApp ResourceType = "host.containerapp"
ResourceTypeOpenAiModel ResourceType = "ai.openai.model"
ResourceTypeMessagingEventHubs ResourceType = "messaging.eventhubs"
ResourceTypeMessagingServiceBus ResourceType = "messaging.servicebus"
ResourceTypeStorage ResourceType = "storage"
)

func (r ResourceType) String() string {
Expand All @@ -43,6 +47,10 @@ func (r ResourceType) String() string {
return "Container App"
case ResourceTypeOpenAiModel:
return "Open AI Model"
case ResourceTypeMessagingEventHubs:
return "Event Hubs"
case ResourceTypeMessagingServiceBus:
return "Service Bus"
case ResourceTypeStorage:
return "Storage Account"
}
Expand Down Expand Up @@ -82,22 +90,22 @@ func (r *ResourceConfig) MarshalYAML() (interface{}, error) {
return nil
}

var errMarshal error
switch raw.Type {
case ResourceTypeOpenAiModel:
err := marshalRawProps(raw.Props.(AIModelProps))
if err != nil {
return nil, err
}
errMarshal = marshalRawProps(raw.Props.(AIModelProps))
case ResourceTypeHostContainerApp:
err := marshalRawProps(raw.Props.(ContainerAppProps))
if err != nil {
return nil, err
}
errMarshal = marshalRawProps(raw.Props.(ContainerAppProps))
case ResourceTypeMessagingEventHubs:
errMarshal = marshalRawProps(raw.Props.(EventHubsProps))
case ResourceTypeMessagingServiceBus:
errMarshal = marshalRawProps(raw.Props.(ServiceBusProps))
case ResourceTypeStorage:
err := marshalRawProps(raw.Props.(StorageProps))
if err != nil {
return nil, err
}
errMarshal = marshalRawProps(raw.Props.(StorageProps))
}

if errMarshal != nil {
return nil, errMarshal
}

return raw, nil
Expand Down Expand Up @@ -137,6 +145,18 @@ func (r *ResourceConfig) UnmarshalYAML(value *yaml.Node) error {
return err
}
raw.Props = cap
case ResourceTypeMessagingEventHubs:
ehp := EventHubsProps{}
if err := unmarshalProps(&ehp); err != nil {
return err
}
raw.Props = ehp
case ResourceTypeMessagingServiceBus:
sbp := ServiceBusProps{}
if err := unmarshalProps(&sbp); err != nil {
return err
}
raw.Props = sbp
case ResourceTypeStorage:
sp := StorageProps{}
if err := unmarshalProps(&sp); err != nil {
Expand Down Expand Up @@ -171,6 +191,15 @@ type AIModelPropsModel struct {
Version string `yaml:"version,omitempty"`
}

type ServiceBusProps struct {
Queues []string `yaml:"queues,omitempty"`
Topics []string `yaml:"topics,omitempty"`
}

type EventHubsProps struct {
Hubs []string `yaml:"hubs,omitempty"`
}

type StorageProps struct {
Containers []string `yaml:"containers,omitempty"`
}
Loading
Loading