Skip to content
Open
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
78 changes: 74 additions & 4 deletions cmd/lbc-migrate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@ package main
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"

"github.com/spf13/cobra"
networking "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway"
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/console"
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/reader"
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/translate"
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/warnings"
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/writer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
)

const defaultOutputDir = "./gateway-output"
Expand All @@ -24,6 +34,8 @@ func main() {

func newRootCommand() *cobra.Command {
opts := &ingress2gateway.MigrateOptions{}
consoleOpts := &ConsoleOptions{Port: 8080}
var consoleMode bool

cmd := &cobra.Command{
Use: "lbc-migrate",
Expand All @@ -32,16 +44,27 @@ func newRootCommand() *cobra.Command {
resources into Gateway API equivalents (Gateway, HTTPRoute, LoadBalancerConfiguration,
TargetGroupConfiguration, ListenerRuleConfiguration etc).

Input can come from YAML/JSON files, a directory of manifest files, or a live Kubernetes cluster.`,
Input can come from YAML/JSON files, a directory of manifest files, or a live Kubernetes cluster.

Use --console to launch a local web UI that compares ingress and gateway dry-run models side by side.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if consoleMode {
return runConsole(cmd.Context(), consoleOpts)
}
if err := validateFlags(opts); err != nil {
return err
}
return runMigrate(cmd.Context(), opts)
},
}

// Console flags
cmd.Flags().BoolVar(&consoleMode, "console", false,
"Launch the migration console web UI to compare ingress and gateway dry-run models")
cmd.Flags().IntVar(&consoleOpts.Port, "port", 8080,
Comment thread
shuqz marked this conversation as resolved.
"Local port for the console web server (only with --console)")

// Input flags
cmd.Flags().StringSliceVarP(&opts.Files, "file", "f", nil,
"Comma-separated input YAML/JSON file paths (e.g. -f file1.yaml,file2.yaml)")
Expand All @@ -67,9 +90,10 @@ Input can come from YAML/JSON files, a directory of manifest files, or a live Ku
cmd.Flags().StringVar(&opts.Split, "split", ingress2gateway.SplitModeNone,
"Split output layout. Empty (default) writes one combined file; 'namespace' writes one file per namespace plus a gatewayclass file for cluster-scoped resources")

// Dry-run flag
cmd.Flags().BoolVar(&opts.DryRun, "dry-run", false,
"Add gateway.k8s.aws/dry-run annotation to generated Gateway manifests so LBC previews the generated AWS resources without creating them")
// Dry-run flag: default to true so users preview the generated model before
// creating real AWS resources. Pass --dry-run=false to opt out.
cmd.Flags().BoolVar(&opts.DryRun, "dry-run", true,
"Add gateway.k8s.aws/dry-run annotation to generated Gateway manifests so LBC previews the generated AWS resources without creating them. Pass --dry-run=false to generate live Gateway manifests.")

return cmd
}
Expand Down Expand Up @@ -137,3 +161,49 @@ func runMigrate(ctx context.Context, opts *ingress2gateway.MigrateOptions) error

return ingress2gateway.Migrate(ctx, *opts, readFunc, translate.Translate, writeFunc)
}

// ConsoleOptions holds the flags for --console mode.
type ConsoleOptions struct {
Port int
}

func runConsole(ctx context.Context, opts *ConsoleOptions) error {
scheme := runtime.NewScheme()
_ = clientgoscheme.AddToScheme(scheme)
_ = gwv1.Install(scheme)
_ = networking.AddToScheme(scheme)

restConfig, err := config.GetConfig()
if err != nil {
return fmt.Errorf("failed to get kubeconfig: %w", err)
}

k8sClient, err := client.New(restConfig, client.Options{Scheme: scheme})
if err != nil {
return fmt.Errorf("failed to create kubernetes client: %w", err)
}

server := console.NewConsoleServer(k8sClient)
addr := fmt.Sprintf("localhost:%d", opts.Port)

httpServer := &http.Server{
Addr: addr,
Handler: server.Handler(),
}

sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)

go func() {
<-sigCh
fmt.Fprintln(os.Stderr, "\nShutting down...")
httpServer.Shutdown(context.Background())
}()

fmt.Fprintf(os.Stderr, "Console running at http://%s\nPress Ctrl+C to stop.\n", addr)

if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
return fmt.Errorf("failed to start console on %s: %w\nUse --port to specify a different port", addr, err)
}
return nil
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/guide/gateway/assets/console/diff-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/guide/gateway/assets/console/landing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading