[DRAFT] Patrones recomendados para manejar provisión de recursos cloud
// main.go
package main
import (
"context"
"fmt"
"log"
)
// ==== CONFIGURATION STRUCTS ====
type VMConfig struct {
Name string
Size string
}
type NetConfig struct {
Name string
CidrBlock string
ResourceID string
}
// ==== RESOURCE MANAGERS (One per resource type) ====
type VMManager struct{}
func (m *VMManager) Exists(ctx context.Context, spec VMConfig) (bool, error) {
// Simulate check (normally query Azure SDK)
log.Printf("[VMManager] Checking existence of VM: %s", spec.Name)
return false, nil
}
func (m *VMManager) Provision(ctx context.Context, spec VMConfig) error {
// Call Azure SDK to create VM, here simplified
log.Printf("[VMManager] Provisioning VM: %s (%s)", spec.Name, spec.Size)
return nil
}
type NetManager struct{}
func (m *NetManager) Exists(ctx context.Context, spec NetConfig) (bool, error) {
log.Printf("[NetManager] Checking existence of Network: %s", spec.Name)
return false, nil
}
func (m *NetManager) Provision(ctx context.Context, spec NetConfig) error {
log.Printf("[NetManager] Provisioning Network: %s (%s)", spec.Name, spec.CidrBlock)
return nil
}
// ==== STEP INTERFACES AND IMPLEMENTATIONS ====
type Step interface {
Name() string
Run(ctx context.Context) error
}
type VMProvisionStep struct {
Spec VMConfig
Manager *VMManager
}
func (s *VMProvisionStep) Name() string { return "VMProvision: " + s.Spec.Name }
func (s *VMProvisionStep) Run(ctx context.Context) error {
// Step can check preconditions if desired
exists, err := s.Manager.Exists(ctx, s.Spec)
if err != nil {
return err
}
if exists {
log.Printf("[Step][VMProvision] VM %s already exists.", s.Spec.Name)
return nil
}
return s.Manager.Provision(ctx, s.Spec)
}
type NetProvisionStep struct {
Spec NetConfig
Manager *NetManager
}
func (s *NetProvisionStep) Name() string { return "NetProvision: " + s.Spec.Name }
func (s *NetProvisionStep) Run(ctx context.Context) error {
exists, err := s.Manager.Exists(ctx, s.Spec)
if err != nil {
return err
}
if exists {
log.Printf("[Step][NetProvision] Network %s already exists.", s.Spec.Name)
return nil
}
return s.Manager.Provision(ctx, s.Spec)
}
// ==== RUNNER ====
type Runner struct {
steps []Step
}
func (r *Runner) AddStep(step Step) {
r.steps = append(r.steps, step)
}
func (r *Runner) Execute(ctx context.Context) error {
for _, step := range r.steps {
log.Printf("[Runner] Executing: %s", step.Name())
if err := step.Run(ctx); err != nil {
return fmt.Errorf("failed on step %s: %w", step.Name(), err)
}
}
return nil
}
// ==== MAIN PROGRAM ====
func main() {
ctx := context.Background()
vmMan := &VMManager{}
netMan := &NetManager{}
// Configs - in real program, loaded from YAML or similar
vmSpecs := []VMConfig{
{Name: "web-01", Size: "Standard_DS1_v2"},
{Name: "db-01", Size: "Standard_B2ms"},
}
netSpecs := []NetConfig{
{Name: "vnet-dev", CidrBlock: "10.0.0.0/16"},
}
runner := &Runner{}
// Network(s) provisioning always before VMs provisioning (example of dependency ordering)
for _, n := range netSpecs {
runner.AddStep(&NetProvisionStep{Spec: n, Manager: netMan})
}
for _, v := range vmSpecs {
runner.AddStep(&VMProvisionStep{Spec: v, Manager: vmMan})
}
if err := runner.Execute(ctx); err != nil {
log.Fatalf("Provisioning failed: %v", err)
}
log.Println("Provisioning workflow finished successfully.")
}
Notas:
Puedes aumentar la lógica en Exists y Provision para interactuar realmente con SDKs, locks, validaciones, etc.
Cada Step encapsula el detalle operativo usando su respectivo Manager (cada uno de los cuales puede crecer y especializarse).
El Runner controla el flujo, el orden y el manejo de errores.
Es flexible para añadir pasos de validación, precondiciones, pasos de destrucción (
DestroyStep), etc.Este ejemplo ejecuta primero las redes y luego las VMs, respetando un posible orden de dependencias.
19 June 2025