Projectos Help

[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