diff --git a/CubeMaster/cmd/cubemastercli/commands/cubebox/net.go b/CubeMaster/cmd/cubemastercli/commands/cubebox/net.go new file mode 100644 index 0000000..4e95b90 --- /dev/null +++ b/CubeMaster/cmd/cubemastercli/commands/cubebox/net.go @@ -0,0 +1,77 @@ +package cubebox + +import ( + "net" + + "github.com/tencentcloud/CubeSandbox/CubeMaster/pkg/service/sandbox/types" + "github.com/urfave/cli" +) + +const ( + keyAllowInternetAccess = "allow-internet-access" + keyAllowOutCIDR = "allow-out-cidr" + keyDenyOutCIDR = "deny-out-cidr" +) + +func parseCubeVSParams(c *cli.Context) (*types.CubeVSContext, error) { + if !c.IsSet(keyAllowInternetAccess) && + len(c.StringSlice(keyAllowOutCIDR)) == 0 && + len(c.StringSlice(keyDenyOutCIDR)) == 0 { + return nil, nil + } + + params := &types.CubeVSContext{} + if c.IsSet(keyAllowInternetAccess) { + val := c.Bool(keyAllowInternetAccess) + params.AllowInternetAccess = &val + } + for _, v := range c.StringSlice(keyAllowOutCIDR) { + _, _, err := net.ParseCIDR(v) + if err != nil { + return nil, err + } + params.AllowOut = append(params.AllowOut, v) + } + for _, v := range c.StringSlice(keyDenyOutCIDR) { + _, _, err := net.ParseCIDR(v) + if err != nil { + return nil, err + } + params.DenyOut = append(params.DenyOut, v) + } + + return params, nil +} + +func mergeCubeVSParams(c *cli.Context, base *types.CubeVSContext) (*types.CubeVSContext, error) { + if !c.IsSet(keyAllowInternetAccess) && + len(c.StringSlice(keyAllowOutCIDR)) == 0 && + len(c.StringSlice(keyDenyOutCIDR)) == 0 { + return base, nil + } + + if base == nil { + base = &types.CubeVSContext{} + } + + if c.IsSet(keyAllowInternetAccess) { + val := c.Bool(keyAllowInternetAccess) + base.AllowInternetAccess = &val + } + for _, v := range c.StringSlice(keyAllowOutCIDR) { + _, _, err := net.ParseCIDR(v) + if err != nil { + return nil, err + } + base.AllowOut = append(base.AllowOut, v) + } + for _, v := range c.StringSlice(keyDenyOutCIDR) { + _, _, err := net.ParseCIDR(v) + if err != nil { + return nil, err + } + base.DenyOut = append(base.DenyOut, v) + } + + return base, nil +} diff --git a/CubeMaster/cmd/cubemastercli/commands/cubebox/template.go b/CubeMaster/cmd/cubemastercli/commands/cubebox/template.go index 908bfa7..9f88d00 100644 --- a/CubeMaster/cmd/cubemastercli/commands/cubebox/template.go +++ b/CubeMaster/cmd/cubemastercli/commands/cubebox/template.go @@ -112,177 +112,6 @@ type templateDeleteRequest struct { Sync bool `json:"sync,omitempty"` } -func mergeCubeVSContextFlags(c *cli.Context, existing *types.CubeVSContext) *types.CubeVSContext { - hasAllowInternetAccess := c.IsSet("allow-internet-access") - allowOut := dedupeCIDRs(c.StringSlice("allow-out-cidr")) - denyOut := dedupeCIDRs(c.StringSlice("deny-out-cidr")) - return mergeCubeVSContextValues(existing, hasAllowInternetAccess, c.Bool("allow-internet-access"), allowOut, denyOut) -} - -func mergeCubeVSContextValues(existing *types.CubeVSContext, hasAllowInternetAccess bool, allowInternetAccess bool, allowOut []string, denyOut []string) *types.CubeVSContext { - if !hasAllowInternetAccess && len(allowOut) == 0 && len(denyOut) == 0 { - return existing - } - - out := cloneCubeVSContext(existing) - if out == nil { - out = &types.CubeVSContext{} - } - if hasAllowInternetAccess { - out.AllowInternetAccess = &allowInternetAccess - } - if len(allowOut) > 0 { - out.AllowOut = appendUniqueCIDRs(out.AllowOut, allowOut) - } - if len(denyOut) > 0 { - out.DenyOut = appendUniqueCIDRs(out.DenyOut, denyOut) - } - return out -} - -type createFromImageExtraCubeVSFlags struct { - hasAllowInternetAccess bool - allowInternetAccess bool - allowOut []string - denyOut []string -} - -func mergeCreateFromImageCubeVSContextFlags(c *cli.Context, existing *types.CubeVSContext) (*types.CubeVSContext, error) { - extra, err := parseCreateFromImageExtraCubeVSFlags(c) - if err != nil { - return nil, err - } - hasAllowInternetAccess := c.IsSet("allow-internet-access") || extra.hasAllowInternetAccess - allowInternetAccess := c.Bool("allow-internet-access") - if extra.hasAllowInternetAccess { - allowInternetAccess = extra.allowInternetAccess - } - allowOut := appendUniqueCIDRs(dedupeCIDRs(c.StringSlice("allow-out-cidr")), extra.allowOut) - denyOut := appendUniqueCIDRs(dedupeCIDRs(c.StringSlice("deny-out-cidr")), extra.denyOut) - return mergeCubeVSContextValues(existing, hasAllowInternetAccess, allowInternetAccess, allowOut, denyOut), nil -} - -func parseCreateFromImageExtraCubeVSFlags(c *cli.Context) (*createFromImageExtraCubeVSFlags, error) { - extraArgs := make([]string, 0, c.NArg()) - for i := 0; i < c.NArg(); i++ { - extraArgs = append(extraArgs, c.Args().Get(i)) - } - if len(extraArgs) == 0 { - return &createFromImageExtraCubeVSFlags{}, nil - } - extra := &createFromImageExtraCubeVSFlags{} - idx := 0 - - if c.IsSet("allow-internet-access") { - if value, ok := parseBoolToken(extraArgs[idx]); ok { - extra.hasAllowInternetAccess = true - extra.allowInternetAccess = value - idx++ - } - } - - for idx < len(extraArgs) { - arg := extraArgs[idx] - switch { - case arg == "--allow-out-cidr": - idx++ - if idx >= len(extraArgs) { - return nil, errors.New("--allow-out-cidr requires a value") - } - extra.allowOut = append(extra.allowOut, extraArgs[idx]) - idx++ - case strings.HasPrefix(arg, "--allow-out-cidr="): - extra.allowOut = append(extra.allowOut, strings.TrimPrefix(arg, "--allow-out-cidr=")) - idx++ - case arg == "--deny-out-cidr": - idx++ - if idx >= len(extraArgs) { - return nil, errors.New("--deny-out-cidr requires a value") - } - extra.denyOut = append(extra.denyOut, extraArgs[idx]) - idx++ - case strings.HasPrefix(arg, "--deny-out-cidr="): - extra.denyOut = append(extra.denyOut, strings.TrimPrefix(arg, "--deny-out-cidr=")) - idx++ - case arg == "--allow-internet-access": - idx++ - if idx >= len(extraArgs) { - return nil, errors.New("--allow-internet-access requires true or false when passed as a trailing argument") - } - value, ok := parseBoolToken(extraArgs[idx]) - if !ok { - return nil, fmt.Errorf("invalid --allow-internet-access value %q: want true or false", extraArgs[idx]) - } - extra.hasAllowInternetAccess = true - extra.allowInternetAccess = value - idx++ - case strings.HasPrefix(arg, "--allow-internet-access="): - value, ok := parseBoolToken(strings.TrimPrefix(arg, "--allow-internet-access=")) - if !ok { - return nil, fmt.Errorf("invalid --allow-internet-access value %q: want true or false", strings.TrimPrefix(arg, "--allow-internet-access=")) - } - extra.hasAllowInternetAccess = true - extra.allowInternetAccess = value - idx++ - default: - return nil, fmt.Errorf("unexpected positional or trailing argument %q; use --allow-internet-access=false or place bool values at the end only when explicitly supported", arg) - } - } - - extra.allowOut = dedupeCIDRs(extra.allowOut) - extra.denyOut = dedupeCIDRs(extra.denyOut) - return extra, nil -} - -func parseBoolToken(value string) (bool, bool) { - switch strings.ToLower(strings.TrimSpace(value)) { - case "true": - return true, true - case "false": - return false, true - default: - return false, false - } -} - -func cloneCubeVSContext(in *types.CubeVSContext) *types.CubeVSContext { - if in == nil { - return nil - } - out := &types.CubeVSContext{ - AllowOut: append([]string(nil), in.AllowOut...), - DenyOut: append([]string(nil), in.DenyOut...), - } - if in.AllowInternetAccess != nil { - allowInternetAccess := *in.AllowInternetAccess - out.AllowInternetAccess = &allowInternetAccess - } - return out -} - -func dedupeCIDRs(values []string) []string { - return appendUniqueCIDRs(nil, values) -} - -func appendUniqueCIDRs(base []string, extra []string) []string { - seen := make(map[string]struct{}, len(base)+len(extra)) - out := append([]string(nil), base...) - for _, cidr := range base { - seen[cidr] = struct{}{} - } - for _, cidr := range extra { - if cidr == "" { - continue - } - if _, ok := seen[cidr]; ok { - continue - } - seen[cidr] = struct{}{} - out = append(out, cidr) - } - return out -} - func formatCubeVSContext(ctx *types.CubeVSContext) string { if ctx == nil { return "allow_internet_access=default(true) allow_out=[] deny_out=[]" @@ -416,7 +245,10 @@ var TemplateCreateCommand = cli.Command{ if scope := c.StringSlice("node"); len(scope) > 0 { req.DistributionScope = scope } - req.CubeVSContext = mergeCubeVSContextFlags(c, req.CubeVSContext) + req.CubeVSContext, err = mergeCubeVSParams(c, req.CubeVSContext) + if err != nil { + return err + } serverList = getServerAddrs(c) if len(serverList) == 0 { @@ -702,7 +534,10 @@ var TemplateCommitCommand = cli.Command{ createReq.Annotations = map[string]string{} } createReq.Annotations[constants.CubeAnnotationAppSnapshotTemplateID] = templateID - createReq.CubeVSContext = mergeCubeVSContextFlags(c, createReq.CubeVSContext) + createReq.CubeVSContext, err = mergeCubeVSParams(c, createReq.CubeVSContext) + if err != nil { + return err + } req := &templateCommitRequest{ RequestID: requestID, @@ -806,7 +641,7 @@ var TemplateCreateFromImageCommand = cli.Command{ RegistryPassword: c.String("registry-password"), ContainerOverrides: containerOverrides, } - req.CubeVSContext, err = mergeCreateFromImageCubeVSContextFlags(c, req.CubeVSContext) + req.CubeVSContext, err = parseCubeVSParams(c) if err != nil { return err } diff --git a/CubeMaster/cmd/cubemastercli/commands/cubebox/template_test.go b/CubeMaster/cmd/cubemastercli/commands/cubebox/template_test.go index 28b50b3..0fd6fd4 100644 --- a/CubeMaster/cmd/cubemastercli/commands/cubebox/template_test.go +++ b/CubeMaster/cmd/cubemastercli/commands/cubebox/template_test.go @@ -9,7 +9,6 @@ import ( "strings" "testing" - "github.com/tencentcloud/CubeSandbox/CubeMaster/pkg/service/sandbox/types" "github.com/urfave/cli" ) @@ -71,46 +70,6 @@ func TestCreateCommandParsesNodeScope(t *testing.T) { } } -func TestMergeCreateFromImageCubeVSContextFlagsEqualsSyntax(t *testing.T) { - ctx := newCreateFromImageContext(t, []string{ - "--allow-internet-access=false", - "--allow-out-cidr", "172.67.0.0/16", - "--deny-out-cidr", "10.0.0.0/8", - }) - - got, err := mergeCreateFromImageCubeVSContextFlags(ctx, nil) - if err != nil { - t.Fatalf("mergeCreateFromImageCubeVSContextFlags error=%v", err) - } - if got == nil || got.AllowInternetAccess == nil || *got.AllowInternetAccess { - t.Fatalf("AllowInternetAccess=%v, want false", got) - } - if len(got.AllowOut) != 1 || got.AllowOut[0] != "172.67.0.0/16" { - t.Fatalf("AllowOut=%v, want [172.67.0.0/16]", got.AllowOut) - } - if len(got.DenyOut) != 1 || got.DenyOut[0] != "10.0.0.0/8" { - t.Fatalf("DenyOut=%v, want [10.0.0.0/8]", got.DenyOut) - } -} - -func TestMergeCreateFromImageCubeVSContextFlagsSupportsTrailingFalse(t *testing.T) { - ctx := newCreateFromImageContext(t, []string{ - "--allow-internet-access", "false", - "--allow-out-cidr", "172.67.0.0/16", - }) - - got, err := mergeCreateFromImageCubeVSContextFlags(ctx, nil) - if err != nil { - t.Fatalf("mergeCreateFromImageCubeVSContextFlags error=%v", err) - } - if got == nil || got.AllowInternetAccess == nil || *got.AllowInternetAccess { - t.Fatalf("AllowInternetAccess=%v, want false", got) - } - if len(got.AllowOut) != 1 || got.AllowOut[0] != "172.67.0.0/16" { - t.Fatalf("AllowOut=%v, want [172.67.0.0/16]", got.AllowOut) - } -} - func TestCreateFromImageCommandParsesNodeScope(t *testing.T) { ctx := newCreateFromImageContext(t, []string{ "--node", "node-a", @@ -121,32 +80,6 @@ func TestCreateFromImageCommandParsesNodeScope(t *testing.T) { } } -func TestMergeCreateFromImageCubeVSContextFlagsRejectsUnexpectedArgs(t *testing.T) { - ctx := newCreateFromImageContext(t, []string{ - "--allow-internet-access", "false", - "unexpected", - }) - - _, err := mergeCreateFromImageCubeVSContextFlags(ctx, nil) - if err == nil { - t.Fatal("expected error for unexpected trailing argument") - } -} - -func TestMergeCubeVSContextValuesPreservesExistingCIDRs(t *testing.T) { - existing := &types.CubeVSContext{ - AllowOut: []string{"192.168.0.0/16"}, - } - - got := mergeCubeVSContextValues(existing, true, false, []string{"172.67.0.0/16"}, nil) - if got == nil || got.AllowInternetAccess == nil || *got.AllowInternetAccess { - t.Fatalf("AllowInternetAccess=%v, want false", got) - } - if len(got.AllowOut) != 2 || got.AllowOut[0] != "192.168.0.0/16" || got.AllowOut[1] != "172.67.0.0/16" { - t.Fatalf("AllowOut=%v, want merged CIDRs", got.AllowOut) - } -} - func TestRedoCommandParsesNodeScope(t *testing.T) { ctx := newRedoContext(t, []string{ "--template-id", "tpl-1",