Skip to content

Commit e9339ce

Browse files
authored
Merge pull request #4728 from shuqz/in-cluster-console
[feat i2g]add in-cluster console for model comparison
2 parents 62144b0 + acba0e0 commit e9339ce

18 files changed

Lines changed: 4425 additions & 25 deletions

File tree

cmd/lbc-migrate/main.go

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,25 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"os"
8+
"os/signal"
79
"strings"
10+
"syscall"
811

912
"github.com/spf13/cobra"
13+
networking "k8s.io/api/networking/v1"
14+
"k8s.io/apimachinery/pkg/runtime"
15+
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
1016
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway"
17+
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/console"
1118
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/reader"
1219
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/translate"
1320
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/warnings"
1421
"sigs.k8s.io/aws-load-balancer-controller/pkg/ingress2gateway/writer"
22+
"sigs.k8s.io/controller-runtime/pkg/client"
23+
"sigs.k8s.io/controller-runtime/pkg/client/config"
24+
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
1525
)
1626

1727
const defaultOutputDir = "./gateway-output"
@@ -25,6 +35,8 @@ func main() {
2535

2636
func newRootCommand() *cobra.Command {
2737
opts := &ingress2gateway.MigrateOptions{}
38+
consoleOpts := &ConsoleOptions{Port: 8080}
39+
var consoleMode bool
2840

2941
cmd := &cobra.Command{
3042
Use: "lbc-migrate",
@@ -33,16 +45,27 @@ func newRootCommand() *cobra.Command {
3345
resources into Gateway API equivalents (Gateway, HTTPRoute, LoadBalancerConfiguration,
3446
TargetGroupConfiguration, ListenerRuleConfiguration etc).
3547
36-
Input can come from YAML/JSON files, a directory of manifest files, or a live Kubernetes cluster.`,
48+
Input can come from YAML/JSON files, a directory of manifest files, or a live Kubernetes cluster.
49+
50+
Use --console to launch a local web UI that compares ingress and gateway dry-run models side by side.`,
3751
SilenceUsage: true,
3852
RunE: func(cmd *cobra.Command, args []string) error {
53+
if consoleMode {
54+
return runConsole(cmd.Context(), consoleOpts)
55+
}
3956
if err := validateFlags(opts); err != nil {
4057
return err
4158
}
4259
return runMigrate(cmd.Context(), opts)
4360
},
4461
}
4562

63+
// Console flags
64+
cmd.Flags().BoolVar(&consoleMode, "console", false,
65+
"Launch the migration console web UI to compare ingress and gateway dry-run models")
66+
cmd.Flags().IntVar(&consoleOpts.Port, "port", 8080,
67+
"Local port for the console web server (only with --console)")
68+
4669
// Input flags
4770
cmd.Flags().StringSliceVarP(&opts.Files, "file", "f", nil,
4871
"Comma-separated input YAML/JSON file paths (e.g. -f file1.yaml,file2.yaml)")
@@ -70,9 +93,10 @@ Input can come from YAML/JSON files, a directory of manifest files, or a live Ku
7093
cmd.Flags().StringVar(&opts.Split, "split", ingress2gateway.SplitModeNone,
7194
"Split output layout. Empty (default) writes one combined file; 'namespace' writes one file per namespace plus a gatewayclass file for cluster-scoped resources")
7295

73-
// Dry-run flag
74-
cmd.Flags().BoolVar(&opts.DryRun, "dry-run", false,
75-
"Add gateway.k8s.aws/dry-run annotation to generated Gateway manifests so LBC previews the generated AWS resources without creating them")
96+
// Dry-run flag: default to true so users preview the generated model before
97+
// creating real AWS resources. Pass --dry-run=false to opt out.
98+
cmd.Flags().BoolVar(&opts.DryRun, "dry-run", true,
99+
"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.")
76100

77101
return cmd
78102
}
@@ -156,3 +180,49 @@ func runMigrate(ctx context.Context, opts *ingress2gateway.MigrateOptions) error
156180

157181
return ingress2gateway.Migrate(ctx, *opts, readFunc, translate.Translate, writeFunc)
158182
}
183+
184+
// ConsoleOptions holds the flags for --console mode.
185+
type ConsoleOptions struct {
186+
Port int
187+
}
188+
189+
func runConsole(ctx context.Context, opts *ConsoleOptions) error {
190+
scheme := runtime.NewScheme()
191+
_ = clientgoscheme.AddToScheme(scheme)
192+
_ = gwv1.Install(scheme)
193+
_ = networking.AddToScheme(scheme)
194+
195+
restConfig, err := config.GetConfig()
196+
if err != nil {
197+
return fmt.Errorf("failed to get kubeconfig: %w", err)
198+
}
199+
200+
k8sClient, err := client.New(restConfig, client.Options{Scheme: scheme})
201+
if err != nil {
202+
return fmt.Errorf("failed to create kubernetes client: %w", err)
203+
}
204+
205+
server := console.NewConsoleServer(k8sClient)
206+
addr := fmt.Sprintf("localhost:%d", opts.Port)
207+
208+
httpServer := &http.Server{
209+
Addr: addr,
210+
Handler: server.Handler(),
211+
}
212+
213+
sigCh := make(chan os.Signal, 1)
214+
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
215+
216+
go func() {
217+
<-sigCh
218+
fmt.Fprintln(os.Stderr, "\nShutting down...")
219+
httpServer.Shutdown(context.Background())
220+
}()
221+
222+
fmt.Fprintf(os.Stderr, "Console running at http://%s\nPress Ctrl+C to stop.\n", addr)
223+
224+
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
225+
return fmt.Errorf("failed to start console on %s: %w\nUse --port to specify a different port", addr, err)
226+
}
227+
return nil
228+
}

go.mod

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ require (
3535
github.com/spf13/pflag v1.0.10
3636
github.com/stretchr/testify v1.11.1
3737
go.uber.org/zap v1.27.1
38-
golang.org/x/net v0.53.0
38+
golang.org/x/net v0.55.0
3939
golang.org/x/time v0.14.0
4040
gomodules.xyz/jsonpatch/v2 v2.4.0
4141
google.golang.org/grpc v1.78.0
@@ -165,14 +165,14 @@ require (
165165
go.uber.org/multierr v1.11.0 // indirect
166166
go.yaml.in/yaml/v2 v2.4.3 // indirect
167167
go.yaml.in/yaml/v3 v3.0.4 // indirect
168-
golang.org/x/crypto v0.50.0 // indirect
169-
golang.org/x/mod v0.34.0 // indirect
168+
golang.org/x/crypto v0.51.0 // indirect
169+
golang.org/x/mod v0.35.0 // indirect
170170
golang.org/x/oauth2 v0.34.0 // indirect
171171
golang.org/x/sync v0.20.0 // indirect
172-
golang.org/x/sys v0.43.0 // indirect
173-
golang.org/x/term v0.42.0 // indirect
174-
golang.org/x/text v0.36.0 // indirect
175-
golang.org/x/tools v0.43.0 // indirect
172+
golang.org/x/sys v0.45.0 // indirect
173+
golang.org/x/term v0.43.0 // indirect
174+
golang.org/x/text v0.37.0 // indirect
175+
golang.org/x/tools v0.44.0 // indirect
176176
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect
177177
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
178178
gopkg.in/inf.v0 v0.9.1 // indirect

go.sum

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -503,13 +503,13 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
503503
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
504504
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
505505
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
506-
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
507-
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
506+
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
507+
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
508508
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
509509
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
510510
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
511-
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
512-
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
511+
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
512+
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
513513
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
514514
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
515515
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -520,8 +520,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
520520
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
521521
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
522522
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
523-
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
524-
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
523+
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
524+
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
525525
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
526526
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
527527
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -551,27 +551,27 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
551551
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
552552
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
553553
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
554-
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
555-
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
554+
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
555+
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
556556
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
557557
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
558-
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
559-
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
558+
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
559+
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
560560
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
561561
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
562562
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
563563
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
564-
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
565-
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
564+
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
565+
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
566566
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
567567
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
568568
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
569569
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
570570
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
571571
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
572572
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
573-
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
574-
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
573+
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
574+
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
575575
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
576576
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
577577
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

0 commit comments

Comments
 (0)