Skip to content

Commit

Permalink
adding the create sub-command tree logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
elkezza committed Jan 2, 2025
1 parent 7884c91 commit 80ebe78
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
94 changes: 94 additions & 0 deletions cmd/dbaas_acl_create.go
Original file line number Diff line number Diff line change
@@ -1 +1,95 @@
package cmd

import (
"context"
"fmt"
"github.com/exoscale/cli/pkg/globalstate"
v3 "github.com/exoscale/egoscale/v3"
"github.com/spf13/cobra"
)

type dbaasAclCreateCmd struct {
cliCommandSettings `cli-cmd:"-"`

_ bool `cli-cmd:"create"`
Name string `cli-flag:"name" cli-usage:"Name of the DBaaS service"`
Username string `cli-flag:"username" cli-usage:"Username for the ACL entry"`
ServiceType string `cli-flag:"type" cli-short:"t" cli-usage:"Type of the DBaaS service (e.g., kafka opensearch)"`
Pattern string `cli-flag:"pattern" cli-usage:"The pattern for the ACL rule (index* for OpenSearch or topic for Kafka, max 249 characters)"`
Permission string `cli-flag:"permission" cli-usage:"Permission to apply (should be one of admin, read, readwrite, write, or deny (only for OpenSearch))"`
}

// Command aliases (none in this case)
func (c *dbaasAclCreateCmd) cmdAliases() []string { return nil }

// Short description for the command
func (c *dbaasAclCreateCmd) cmdShort() string {
return "Create an ACL entry for a DBaaS service"
}

// Long description for the command
func (c *dbaasAclCreateCmd) cmdLong() string {
return `This command creates an ACL entry for a specified DBaaS service, automatically searching for the service across all available zones.`
}

func (c *dbaasAclCreateCmd) cmdPreRun(cmd *cobra.Command, args []string) error {
return cliCommandDefaultPreRun(c, cmd, args)
}

// Main run logic for showing ACL details
func (c *dbaasAclCreateCmd) cmdRun(cmd *cobra.Command, args []string) error {
ctx := context.Background()

// Validate required inputs
if c.Name == "" || c.Username == "" || c.ServiceType == "" || c.Permission == "" || c.Pattern == "" {
return fmt.Errorf("all --name, --username, --type, --permission and --pattern flags must be specified")
}

// Fetch all available zones
zones, err := globalstate.EgoscaleV3Client.ListZones(ctx)
if err != nil {
return fmt.Errorf("error fetching zones: %w", err)
}

// Iterate through zones to find the service
var serviceZone string
var dbType v3.DBAASDatabaseName
var client *v3.Client
found := false

for _, zone := range zones.Zones {
db, err := dbaasGetV3(ctx, c.Name, string(zone.Name))
if err == nil {
dbType = v3.DBAASDatabaseName(db.Type)
serviceZone = string(zone.Name)
client, err = switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, v3.ZoneName(serviceZone))
if err != nil {
return fmt.Errorf("error initializing client for zone %s: %w", serviceZone, err)
}
found = true
break
}
}

if !found {
return fmt.Errorf("service %q not found in any zone", c.Name)
}
// Validate the service type
if string(dbType) != c.ServiceType {
return fmt.Errorf("service type mismatch: expected %q but got %q for service %q", c.ServiceType, dbType, c.Name)
}

switch dbType {
case "kafka":
return c.createKafka(ctx, client, c.Name)
case "opensearch":
return c.createOpensearch(ctx, client, c.Name)
default:
return fmt.Errorf("create ACL unsupported for service type %q", dbType)
}
}
func init() {
cobra.CheckErr(registerCLICommand(dbaasAclCmd, &dbaasAclCreateCmd{
cliCommandSettings: defaultCLICmdSettings(),
}))
}
35 changes: 35 additions & 0 deletions cmd/dbaas_acl_create_kafka.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cmd

import (
"context"
"fmt"

v3 "github.com/exoscale/egoscale/v3"
)

func (c *dbaasAclCreateCmd) createKafka(ctx context.Context, client *v3.Client, serviceName string) error {
// Define the new Kafka ACL entry
newAcl := v3.DBAASKafkaTopicAclEntry{
Username: c.Username,
Topic: c.Pattern,
Permission: v3.DBAASKafkaTopicAclEntryPermission(c.Permission),
}

// Trigger the creation of the ACL entry
op, err := client.CreateDBAASKafkaTopicAclConfig(ctx, serviceName, newAcl)
if err != nil {
return fmt.Errorf("error creating ACL entry for service %q: %w", serviceName, err)
}

// Use decorateAsyncOperation to handle the operation and provide user feedback
decorateAsyncOperation(fmt.Sprintf("Creating Kafka ACL entry for user %q", c.Username), func() {
op, err = client.Wait(ctx, op, v3.OperationStateSuccess)
})

if err != nil {
return fmt.Errorf("error completing ACL creation: %w", err)
}

fmt.Printf("Kafka ACL entry for user %q successfully created in service %q\n", c.Username, serviceName)
return nil
}
46 changes: 46 additions & 0 deletions cmd/dbaas_acl_create_opensearch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cmd

import (
"context"
"fmt"
v3 "github.com/exoscale/egoscale/v3"
)

func (c *dbaasAclCreateCmd) createOpensearch(ctx context.Context, client *v3.Client, serviceName string) error {
aclsConfig, err := client.GetDBAASOpensearchAclConfig(ctx, serviceName)
if err != nil {
return fmt.Errorf("error fetching ACL configuration for service %q: %w", serviceName, err)
}

// Check if an entry with the same username already exists
for _, acl := range aclsConfig.Acls {
if string(acl.Username) == c.Username {
return fmt.Errorf("ACL entry for username %q already exists in service %q", c.Username, serviceName)
}
}

// Create a new ACL entry
newAcl := v3.DBAASOpensearchAclConfigAcls{
Username: v3.DBAASUserUsername(c.Username),
Rules: []v3.DBAASOpensearchAclConfigAclsRules{
{Index: c.Pattern, Permission: v3.EnumOpensearchRulePermission(c.Permission)},
},
}

// Append the new entry to the existing ACLs
aclsConfig.Acls = append(aclsConfig.Acls, newAcl)

// Update the configuration with the new entry
op, err := client.UpdateDBAASOpensearchAclConfig(ctx, serviceName, *aclsConfig)
if err != nil {
return fmt.Errorf("error updating ACL configuration for service %q: %w", serviceName, err)
}

// Use decorateAsyncOperation to wait for the operation and provide user feedback
decorateAsyncOperation(fmt.Sprintf("Creating ACL entry for user %q", c.Username), func() {
op, err = client.Wait(ctx, op, v3.OperationStateSuccess)
})

fmt.Printf("ACL entry for username %q created successfully in service %q\n", c.Username, serviceName)
return nil
}

0 comments on commit 80ebe78

Please sign in to comment.