Skip to content

Commit 53e6f59

Browse files
authored
attach cr to namespace (#457)
* attach cr to namespace * address code comments
1 parent 5ca520c commit 53e6f59

2 files changed

Lines changed: 207 additions & 69 deletions

File tree

app/namespace.go

Lines changed: 119 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"net/mail"
99
"os"
10+
"reflect"
1011
"strconv"
1112
"strings"
1213

@@ -158,6 +159,12 @@ var (
158159
Aliases: []string{"re"},
159160
Required: false,
160161
}
162+
connectivityRuleIdsFlag = &cli.StringSliceFlag{
163+
Name: connectivityRuleIdsFlagName,
164+
Usage: "The list of connectivity rule IDs, can be used in create namespace, update namespace and get list of connectivity rules. example: --ids id1 --ids id2 --ids id3",
165+
Aliases: []string{"ids"},
166+
Required: false,
167+
}
161168
)
162169

163170
type NamespaceClient struct {
@@ -497,80 +504,90 @@ func ReadCertFilters(ctx *cli.Context) ([]byte, error) {
497504
return certFilterBytes, nil
498505
}
499506

507+
func getCreateNamespaceFlags() []cli.Flag {
508+
baseFlags := []cli.Flag{
509+
RequestIDFlag,
510+
CaCertificateFlag,
511+
&cli.StringFlag{
512+
Name: NamespaceFlagName,
513+
Usage: "The namespace hosted on temporal cloud",
514+
Aliases: []string{"n"},
515+
Required: true,
516+
},
517+
&cli.StringSliceFlag{
518+
Name: namespaceRegionFlagName,
519+
Usage: "Create namespace in specified regions; if multiple regions are selected, the first one will be the active region. See 'tcld account list-regions' to get a list of available regions for your account",
520+
Aliases: []string{"re"},
521+
Required: true,
522+
},
523+
&cli.IntFlag{
524+
Name: RetentionDaysFlagName,
525+
Usage: "The retention of the namespace in days",
526+
Aliases: []string{"rd"},
527+
Value: 30,
528+
},
529+
&cli.StringFlag{
530+
Name: authMethodFlagName,
531+
Usage: "The authentication method to use for the namespace (e.g. 'mtls', 'api_key')",
532+
Value: AuthMethodMTLS,
533+
},
534+
&cli.PathFlag{
535+
Name: CaCertificateFileFlagName,
536+
Usage: "The path to the ca pem file",
537+
Aliases: []string{"cf"},
538+
},
539+
&cli.PathFlag{
540+
Name: certificateFilterFileFlagName,
541+
Usage: `Path to a JSON file that defines the certificate filters that will be added to the namespace. Sample JSON: { "filters": [ { "commonName": "test1" } ] }`,
542+
Aliases: []string{"cff"},
543+
},
544+
&cli.StringFlag{
545+
Name: certificateFilterInputFlagName,
546+
Usage: `JSON that defines the certificate filters that will be added to the namespace. Sample JSON: { "filters": [ { "commonName": "test1" } ] }`,
547+
Aliases: []string{"cfi"},
548+
},
549+
&cli.StringSliceFlag{
550+
Name: searchAttributeFlagName,
551+
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"name=type\"; valid types are: %v", getSearchAttributeTypes()),
552+
Aliases: []string{"sa"},
553+
},
554+
&cli.StringSliceFlag{
555+
Name: userNamespacePermissionFlagName,
556+
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"email=permission\"; valid permissions are: %v", getNamespacePermissionTypes()),
557+
Aliases: []string{"p"},
558+
},
559+
&cli.BoolFlag{
560+
Name: enableDeleteProtectionFlagName,
561+
Usage: "Enable delete protection on the namespace",
562+
Aliases: []string{"edp"},
563+
},
564+
codecEndpointFlag,
565+
codecPassAccessTokenFlag,
566+
codecIncludeCredentialsFlag,
567+
&cli.StringFlag{
568+
Name: cloudProviderFlagName,
569+
Usage: `Cloud provider for the namespace to be created for, currently support [aws, gcp]. For this version, if not specified, we default to aws`,
570+
Aliases: []string{"cp"},
571+
// this is a temporary solution, we will have a follow up version update to make the cloud provider mandatory
572+
Value: CloudProviderAWS,
573+
},
574+
}
575+
576+
if IsFeatureEnabled(ConnectivityRuleFeatureFlag) {
577+
baseFlags = append(baseFlags, connectivityRuleIdsFlag)
578+
}
579+
580+
return baseFlags
581+
}
582+
500583
func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut, error) {
501584
var c *NamespaceClient
502585
subCommands := []*cli.Command{
503586
{
504587
Name: "create",
505588
Usage: "Create a temporal namespace",
506589
Aliases: []string{"c"},
507-
Flags: []cli.Flag{
508-
RequestIDFlag,
509-
CaCertificateFlag,
510-
&cli.StringFlag{
511-
Name: NamespaceFlagName,
512-
Usage: "The namespace hosted on temporal cloud",
513-
Aliases: []string{"n"},
514-
Required: true,
515-
},
516-
&cli.StringSliceFlag{
517-
Name: namespaceRegionFlagName,
518-
Usage: "Create namespace in specified regions; if multiple regions are selected, the first one will be the active region. See 'tcld account list-regions' to get a list of available regions for your account",
519-
Aliases: []string{"re"},
520-
Required: true,
521-
},
522-
&cli.IntFlag{
523-
Name: RetentionDaysFlagName,
524-
Usage: "The retention of the namespace in days",
525-
Aliases: []string{"rd"},
526-
Value: 30,
527-
},
528-
&cli.StringFlag{
529-
Name: authMethodFlagName,
530-
Usage: "The authentication method to use for the namespace (e.g. 'mtls', 'api_key')",
531-
Value: AuthMethodMTLS,
532-
},
533-
&cli.PathFlag{
534-
Name: CaCertificateFileFlagName,
535-
Usage: "The path to the ca pem file",
536-
Aliases: []string{"cf"},
537-
},
538-
&cli.PathFlag{
539-
Name: certificateFilterFileFlagName,
540-
Usage: `Path to a JSON file that defines the certificate filters that will be added to the namespace. Sample JSON: { "filters": [ { "commonName": "test1" } ] }`,
541-
Aliases: []string{"cff"},
542-
},
543-
&cli.StringFlag{
544-
Name: certificateFilterInputFlagName,
545-
Usage: `JSON that defines the certificate filters that will be added to the namespace. Sample JSON: { "filters": [ { "commonName": "test1" } ] }`,
546-
Aliases: []string{"cfi"},
547-
},
548-
&cli.StringSliceFlag{
549-
Name: searchAttributeFlagName,
550-
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"name=type\"; valid types are: %v", getSearchAttributeTypes()),
551-
Aliases: []string{"sa"},
552-
},
553-
&cli.StringSliceFlag{
554-
Name: userNamespacePermissionFlagName,
555-
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"email=permission\"; valid permissions are: %v", getNamespacePermissionTypes()),
556-
Aliases: []string{"p"},
557-
},
558-
&cli.BoolFlag{
559-
Name: enableDeleteProtectionFlagName,
560-
Usage: "Enable delete protection on the namespace",
561-
Aliases: []string{"edp"},
562-
},
563-
codecEndpointFlag,
564-
codecPassAccessTokenFlag,
565-
codecIncludeCredentialsFlag,
566-
&cli.StringFlag{
567-
Name: cloudProviderFlagName,
568-
Usage: `Cloud provider for the namespace to be created for, currently support [aws, gcp]. For this version, if not specified, we default to aws`,
569-
Aliases: []string{"cp"},
570-
// this is a temporary solution, we will have a follow up version update to make the cloud provider mandatory
571-
Value: CloudProviderAWS,
572-
},
573-
},
590+
Flags: getCreateNamespaceFlags(),
574591
Action: func(ctx *cli.Context) error {
575592
n := &namespace.Namespace{
576593
RequestId: ctx.String(RequestIDFlagName),
@@ -722,6 +739,11 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut,
722739
EnableDeleteProtection: ctx.Bool(enableDeleteProtectionFlagName),
723740
}
724741

742+
connectivityRuleIds := ctx.StringSlice(connectivityRuleIdsFlagName)
743+
if len(connectivityRuleIds) > 0 {
744+
n.Spec.ConnectivityRuleIds = connectivityRuleIds
745+
}
746+
725747
return c.createNamespace(n, unp)
726748
},
727749
},
@@ -2113,8 +2135,38 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut,
21132135
exportGCSCommands.Subcommands = append(exportGCSCommands.Subcommands, exportGeneralCommands...)
21142136
exportCommand.Subcommands = append(exportCommand.Subcommands, exportGCSCommands)
21152137

2138+
coonectivityRuleCommand := &cli.Command{
2139+
Name: "set-connectivity-rules",
2140+
Usage: "set the connectivity rules for a namespace",
2141+
Aliases: []string{"scrs"},
2142+
Flags: []cli.Flag{
2143+
NamespaceFlag,
2144+
connectivityRuleIdsFlag,
2145+
},
2146+
Action: func(ctx *cli.Context) error {
2147+
n, err := c.getNamespace(ctx.String(NamespaceFlagName))
2148+
if err != nil {
2149+
return err
2150+
}
2151+
connectivityRuleIds := ctx.StringSlice(connectivityRuleIdsFlagName)
2152+
if len(connectivityRuleIds) == 0 {
2153+
return fmt.Errorf("connectivity rule ids must be provided")
2154+
}
2155+
if reflect.DeepEqual(n.Spec.ConnectivityRuleIds, connectivityRuleIds) {
2156+
return fmt.Errorf("no connectivity rule changes to apply")
2157+
}
2158+
2159+
n.Spec.ConnectivityRuleIds = connectivityRuleIds
2160+
return c.updateNamespace(ctx, n)
2161+
},
2162+
}
2163+
21162164
subCommands = append(subCommands, exportCommand)
21172165

2166+
if IsFeatureEnabled(ConnectivityRuleFeatureFlag) {
2167+
subCommands = append(subCommands, coonectivityRuleCommand)
2168+
}
2169+
21182170
command := &cli.Command{
21192171
Name: "namespace",
21202172
Aliases: []string{"n"},

app/namespace_test.go

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ type NamespaceTestSuite struct {
4242
}
4343

4444
func (s *NamespaceTestSuite) SetupTest() {
45-
err := toggleFeature(GCPSinkFeatureFlag)
46-
s.Require().NoError(err)
45+
if !IsFeatureEnabled(ConnectivityRuleFeatureFlag) {
46+
err := toggleFeature(ConnectivityRuleFeatureFlag)
47+
s.Require().NoError(err)
48+
}
4749

4850
s.mockCtrl = gomock.NewController(s.T())
4951
s.mockService = namespaceservicemock.NewMockNamespaceServiceClient(s.mockCtrl)
@@ -2816,3 +2818,87 @@ func (s *NamespaceTestSuite) TestRemoveNamespaceRegion() {
28162818
})
28172819
}
28182820
}
2821+
2822+
func (s *NamespaceTestSuite) TestSetConnectivityRules() {
2823+
ns := "ns1"
2824+
resourceVersion := "ver1"
2825+
initialRules := []string{"cr-1"}
2826+
newRules := []string{"cr-2", "cr-3"}
2827+
2828+
type morphGetResp func(*namespaceservice.GetNamespaceResponse)
2829+
type morphUpdateReq func(*namespaceservice.UpdateNamespaceRequest)
2830+
2831+
tests := []struct {
2832+
name string
2833+
args []string
2834+
expectGet morphGetResp
2835+
expectErr bool
2836+
expectUpdate morphUpdateReq
2837+
}{
2838+
{
2839+
name: "success",
2840+
args: []string{"namespace", "set-connectivity-rules", "--namespace", ns, "--connectivity-rule-ids", "cr-2", "--connectivity-rule-ids", "cr-3"},
2841+
expectGet: func(g *namespaceservice.GetNamespaceResponse) {
2842+
g.Namespace.Spec.ConnectivityRuleIds = initialRules
2843+
},
2844+
expectUpdate: func(r *namespaceservice.UpdateNamespaceRequest) {
2845+
r.Spec.ConnectivityRuleIds = newRules
2846+
},
2847+
},
2848+
{
2849+
name: "no change",
2850+
args: []string{"namespace", "set-connectivity-rules", "--namespace", ns, "--connectivity-rule-ids", "cr-1"},
2851+
expectGet: func(g *namespaceservice.GetNamespaceResponse) {
2852+
g.Namespace.Spec.ConnectivityRuleIds = initialRules
2853+
},
2854+
expectErr: true,
2855+
},
2856+
{
2857+
name: "missing ids",
2858+
args: []string{"namespace", "set-connectivity-rules", "--namespace", ns},
2859+
expectGet: func(g *namespaceservice.GetNamespaceResponse) {},
2860+
expectErr: true,
2861+
},
2862+
}
2863+
2864+
for _, tc := range tests {
2865+
s.Run(tc.name, func() {
2866+
getResp := namespaceservice.GetNamespaceResponse{
2867+
Namespace: &namespace.Namespace{
2868+
Namespace: ns,
2869+
Spec: &namespace.NamespaceSpec{
2870+
ConnectivityRuleIds: initialRules,
2871+
},
2872+
ResourceVersion: resourceVersion,
2873+
},
2874+
}
2875+
if tc.expectGet != nil {
2876+
tc.expectGet(&getResp)
2877+
s.mockService.EXPECT().GetNamespace(gomock.Any(), &namespaceservice.GetNamespaceRequest{
2878+
Namespace: ns,
2879+
}).Return(&getResp, nil).Times(1)
2880+
}
2881+
2882+
if tc.expectUpdate != nil {
2883+
spec := *(getResp.Namespace.Spec)
2884+
req := namespaceservice.UpdateNamespaceRequest{
2885+
Namespace: ns,
2886+
Spec: &spec,
2887+
ResourceVersion: getResp.Namespace.ResourceVersion,
2888+
}
2889+
tc.expectUpdate(&req)
2890+
s.mockService.EXPECT().UpdateNamespace(gomock.Any(), &req).
2891+
Return(&namespaceservice.UpdateNamespaceResponse{
2892+
RequestStatus: &request.RequestStatus{},
2893+
}, nil).Times(1)
2894+
}
2895+
2896+
err := s.RunCmd(tc.args...)
2897+
if tc.expectErr {
2898+
s.Error(err)
2899+
} else {
2900+
s.NoError(err)
2901+
}
2902+
})
2903+
}
2904+
}

0 commit comments

Comments
 (0)