-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
For sharing review comments #1
base: for-review
Are you sure you want to change the base?
Conversation
Support CIDR in group for security policy
Change thumbprint from sha256 to sha1
Fix nsx requests not using token while token exists
1.Support MatchExpression Operator: 'NotIn', 'Exists', 'DoesNotExist' for VM/Pod/Namespace label selectors in SecurityPolicy 2.Given NSX doesn't support MatchExpression Operator 'In', and only five criteria are allowed currently, which results into a gigantic group expression body to be passed to NSX. So, only allow just one Operator 'In' MatchExpressions with at most of five values in it. 3.Add NSX-T limitation and NSGroup Criteria check
…Support Add MatchExpression support for SecurityPolicy
Update some log output Remove unused test case from transport_test.go
Roundtrip should only return err from base().RoundTrip
This patch will fix 2 issues: 1. start of portRange was mistakenly set into the sourcePorts property in NSX-T. 2. json.Marshal(rule) cannot detect the change of SecurityPolicyPort.
Because that some existing container may already use this port.
Add priority range in SecurityPolicy definition
version and create resources by JWT
Remove application/x-www-form-urlencoded from header
1. When building the expression, if there's only "ncp/pod" in the "value" property, the "ncp/pod" will appear in place of the "tag equals", not of the "scope equals" which we are expecting. This patch will change "ncp/pod" to "ncp/pod|" to fix this issue. 2. If namespaceSelector not set in the peer, the rule should select the pod/vm in the same namespace instead of all namespaces.
Change the probe port from 8383 to 8384
Fix SecurityPolicyPort issues
…ondition_kv Fix the condition issues for pod/vm selector
Ensure all criterion mixed, part 1
Auto decrement page size when 60576 errcode appears
This patch is to refactor PR#55, certieria produced for PodSelector, VMSelector and NamespaceSelector, and make the certieria always to be created as a mixed one by changing cluster tag membery type. For PodSelector, VMSelector: cluster tag membery type is set as Segment For NamespaceSelector: cluster tag membery type is set as SegmentPort
Change certieria produced as a mixed one
This patch is to add MatchExpression UnitTests, fix some typo and a minor code refactor in updateMixedExpressionsMatchExpression
Enforce user cannot create SecPolicy CR in sys ns
Add MatchExpression UnitTests
Use gomonkey to mock struct method Use gomock to mock interface method Update gc function so it could be tested
Add UT for garbage collector
Api manager in config may include port and scheme when searching local thumbprint, it should move the port part and only compare host
…ntegration Support to create subnetport in subnetset
IPPool controller added
Get port number by subnet ID from subnetport store
"Project" and "External_ipv4_blocks" are retrieved from VPCNetworkConfiguration CR instead of NCP ConfigMap. Remove the validation check for these 2 options.
…ve_config Remove validation check for default_project and external_ipv4_blocks
1. Read the real StaticIPAllocation from CR during building NSX subnet. 2. Set StaticIPAllocation to true in default subnetset. 3. Correct the finalizer names of subnet/subnetset.
…rties Fix several subnet/subnetset issues
Fix errors when deleting ip block from ipblock store
logf.SetLogger(logger.ZapLogger()) | ||
cf, err = config.NewNSXOperatorConfigFromFile() | ||
if err != nil { | ||
log.Error(err, "load config file error") | ||
os.Exit(1) | ||
} | ||
|
||
if os.Getenv("NSX_OPERATOR_NAMESPACE") != "" { | ||
nsxOperatorNamespace = os.Getenv("NSX_OPERATOR_NAMESPACE") | ||
} | ||
|
||
if cf.HAEnabled() { | ||
log.Info("HA mode enabled") | ||
} else { | ||
log.Info("HA mode disabled") | ||
} | ||
|
||
if metrics.AreMetricsExposed(cf) { | ||
metrics.InitializePrometheusMetrics() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not proper to be in init
as they will be executed as long as the package is imported, which means you need to prepare a config file even when running unit test for cmd package.
nsxClient := nsx.GetClient(cf) | ||
if nsxClient == nil { | ||
log.Error(err, "failed to get nsx client") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the func could fail to return a valid nsxClient, it should use nil
error to indicate it, instead of returning nil
nsxClient. Currently the code is contradictory, the err
is always nil
as it's not received from the function, and the func
never returns nil
nsxClient, even it fails (Instead, it just log an error`)
nsx-operator/pkg/nsx/client.go
Lines 188 to 197 in acf8557
if !nsxClient.NSXCheckVersion(SecurityPolicy) { | |
err := errors.New("SecurityPolicy feature support check failed") | |
log.Error(err, "initial NSX version check for SecurityPolicy got error") | |
} | |
if !nsxClient.NSXCheckVersion(ServiceAccount) { | |
err := errors.New("NSXServiceAccount feature support check failed") | |
log.Error(err, "initial NSX version check for NSXServiceAccount got error") | |
} | |
return nsxClient |
} | ||
|
||
if cf.CoeConfig.EnableVPCNetwork && commonService.NSXClient.NSXCheckVersion(nsx.VPC) { | ||
log.V(1).Info("VPC mode enabled") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such one time log indicating the enablement of a module could be V(0) as it's few but provide key information.
if subnetService == nil { | ||
lock.Lock() | ||
defer lock.Unlock() | ||
if subnetService == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the func is supposed to be called concurrently, it's not really thread-safe as L48 is without lock acquired.
If the func is not supposed to be called concurrently, the lock is not required at all.
From the usage, I think the lock and the global variable subnetServer
makes it complicated, and it would be hard to use SubnetService in unit test, as you will need to reset the global variable every time after a test writes it.
A simpler and clearer way to initialzie the struct is just expose a constructor to main.go and inject the service to modules which rely on it:
func NewSubnetService(service common.Service) (*SubnetService, error)
...
# main.go
subnetService = subnet.NewSubnetService(commonService)
subnetReconciler.Service = subnetService
...
subnetsetReconciler.Service = subnetService
wg := sync.WaitGroup{} | ||
wgDone := make(chan bool) | ||
fatalErrors := make(chan error) | ||
subnetService := &SubnetService{ | ||
Service: service, | ||
SubnetStore: &SubnetStore{ | ||
ResourceStore: common.ResourceStore{ | ||
Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ | ||
common.TagScopeSubnetCRUID: subnetIndexFunc, | ||
}), | ||
BindingType: model.VpcSubnetBindingType(), | ||
}, | ||
}, | ||
} | ||
|
||
wg.Add(1) | ||
go subnetService.InitializeResourceStore(&wg, fatalErrors, ResourceTypeSubnet, nil, subnetService.SubnetStore) | ||
go func() { | ||
wg.Wait() | ||
close(wgDone) | ||
}() | ||
select { | ||
case <-wgDone: | ||
break | ||
case err := <-fatalErrors: | ||
close(fatalErrors) | ||
return subnetService, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the essential of the code is that it wants to get the result of InitializeResourceStore
synchronously, regardless of success or failure. The usage of the channels and waitGroup makes it really complicated. Why don't just make InitializeResourceStore
return an error?
func NewSubnetService(service common.Service) (*SubnetService, error) {
subnetService := &SubnetService{
Service: service,
SubnetStore: &SubnetStore{
ResourceStore: common.ResourceStore{
Indexer: cache.NewIndexer(keyFunc, cache.Indexers{
common.TagScopeSubnetCRUID: subnetIndexFunc,
}),
BindingType: model.VpcSubnetBindingType(),
},
},
}
if err := subnetService.InitializeResourceStore(ResourceTypeSubnet, nil, subnetService.SubnetStore); err != nil {
return nil, err
}
return subnetService, nil
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides, closing a channel could make goroutines writting to it panic, which is the case of InitializeResourceStore
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the essential of the code is that it wants to get the result of
InitializeResourceStore
synchronously, regardless of success or failure. The usage of the channels and waitGroup makes it really complicated. Why don't just makeInitializeResourceStore
return an error?func NewSubnetService(service common.Service) (*SubnetService, error) { subnetService := &SubnetService{ Service: service, SubnetStore: &SubnetStore{ ResourceStore: common.ResourceStore{ Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ common.TagScopeSubnetCRUID: subnetIndexFunc, }), BindingType: model.VpcSubnetBindingType(), }, }, } if err := subnetService.InitializeResourceStore(ResourceTypeSubnet, nil, subnetService.SubnetStore); err != nil { return nil, err } return subnetService, nil }
For the case of Subnet service, we can just make InitializeResourceStore
just return an error. I think InitializeResourceStore
is designed to use channels/waitgroup to initialize multiple resource stores simultaneously in different goroutines. Taking firewall service as example, it initializes four kinds of resource stores simultaneously.
But I see that most of services ONLY initialize one store, so it also makes sense to simplify InitializeResourceStore
.
vpcInfo, err := common.ParseVPCResourcePath(vpcList.Items[0].Status.NSXResourcePath) | ||
if err != nil { | ||
return "", err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does it guarantee NSXResourcePath
has been set when processing this subnet? If there is no guarantee, errors may be generated randomly which might scare users who are monitoring component logs.
If having a valid NSXResourcePath
is a precondition of creating subnet, perhaps it could skip enqueuing a subnet when VPC is not ready and enqueue associated subnets when VPC is ready.
if len(obj.Spec.SubnetSet) > 0 && len(obj.Spec.Subnet) > 0 { | ||
err := errors.New("subnet and subnetset should not be configured at the same time") | ||
log.Error(err, "failed to get subnet/subnetset of the subnetport", "subnetport", req.NamespacedName) | ||
return common.ResultNormal, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could enforce the validation in CRD schema to ensure at most one SubnetSet/Subnet is set. Otherwise returning the error to make it retry is pointless.
// if attachmentRef.Name == "" { | ||
// defaultVMSubnet = true | ||
// } | ||
old_status := obj.Status.DeepCopy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use consistent naming style: oldStatus
subnetPath = subnet.Status.NSXResourcePath | ||
if len(subnetPath) == 0 { | ||
err := fmt.Errorf("empty NSX resource path from subnet %s", subnet.Name) | ||
return subnetPath, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guess there is no guarantee that NSXResourcePath
is not empty here. Instead of returning error, perhaps it could also skip enqueueing the subnetPort when its subnet's status is not ready, and watch subnet's status update event and make it enqueue associated subnetPorts which are not realized yet.
subnetPath, err := r.AllocateSubnetFromSubnetSet(obj, subnetSet) | ||
if err != nil { | ||
return subnetPath, err | ||
} | ||
return subnetPath, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guess this is related to where @dantingl raised the race condition. Except for adding a lock to the method, there may be another solution:
subnetsetController also watches subsetPorts, and checks if the current capacity is enough by comparing the expected capacity and number of current subsetPorts. In its reconcile func, it auto-scales the subnetSet when the capacity is not enough.
Then subnetPort just waits for available subnet/subnetSet to be available and can unify the implementation.
matchedCondition := getExistingConditionOfType(newCondition.Type, subnetset.Status.Conditions) | ||
|
||
if reflect.DeepEqual(matchedCondition, newCondition) { | ||
log.V(2).Info("conditions already match", "New Condition", newCondition, "Existing Condition", matchedCondition) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use space to connect multi words in the key of structured logging, otherwise it could be hard to differentiate key and value in some cases and hard to use tool to extract key and values. Some suggestions about logging:
https://github.com/tnqn/code-review-comments#logging
return ctrl.NewControllerManagedBy(mgr). | ||
For(&v1alpha1.SubnetSet{}). | ||
WithOptions(controller.Options{ | ||
MaxConcurrentReconciles: runtime.NumCPU(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't make sense to use cpu number as the concurrency of network-intensive tasks, the efficiecy of the application may vary in different environments and unpredictable. It may run well when it's tested in a env but badly in another.
portNums := len(common.ServiceMediator.GetPortsOfSubnet(*subnet.Id)) | ||
if portNums > 0 { | ||
continue | ||
} | ||
if err := r.Service.DeleteSubnet(subnet); err != nil { | ||
log.Error(err, "fail to delete subnet from subnetset cr", "ID", *subnet.Id) | ||
hitError = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could conflict with the code that allocates empty subnet. If #1 (comment) is accepted, perhaps it could implement garbage collection in Reconcile
, it could be retriggered by always returning RequeueAfter as the GCInterval
Initialize subnet service once then inject it to multiple reconcilers instead of initializing service in different reconcilers with a lock ensuring the initialization is invoked once. tnqn#1 (comment)
Add LastTansitionTime in CR status which helps understand when the issue was encountered/resolved when viewing the CR. tnqn#1 (comment)
Add LastTansitionTime in CR status which helps understand when the issue was encountered/resolved when viewing the CR. tnqn#1 (comment)
Add LastTansitionTime in CR status which helps understand when the issue was encountered/resolved when viewing the CR. tnqn#1 (comment)
Add LastTansitionTime in CR status which helps understand when the issue was encountered/resolved when viewing the CR. tnqn#1 (comment)
Initialize subnet service once then inject it to multiple reconcilers instead of initializing service in different reconcilers with a lock ensuring the initialization is invoked once. tnqn#1 (comment)
Add LastTansitionTime in CR status which helps understand when the issue was encountered/resolved when viewing the CR. tnqn#1 (comment)
Remove Subnet/SubnetPort service from mediator as service mediato will be removed from nsx-operator. Subnet/SubnetPort service will only be instantiated once and passed as pointer across controllers. tnqn#1 (comment)
Remove Subnet/SubnetPort service from mediator as service mediato will be removed from nsx-operator. Subnet/SubnetPort service will only be instantiated once and passed as pointer across controllers. tnqn#1 (comment)
Remove Subnet/SubnetPort service from mediator as service mediato will be removed from nsx-operator. Subnet/SubnetPort service will only be instantiated once and passed as pointer across controllers. tnqn#1 (comment)
Remove Subnet/SubnetPort service from mediator as service mediato will be removed from nsx-operator. Subnet/SubnetPort service will only be instantiated once and passed as pointer across controllers. tnqn#1 (comment)
Remove Subnet/SubnetPort service from mediator as service mediato will be removed from nsx-operator. Subnet/SubnetPort service will only be instantiated once and passed as pointer across controllers. tnqn#1 (comment)
Remove Subnet/SubnetPort service from mediator as service mediato will be removed from nsx-operator. Subnet/SubnetPort service will only be instantiated once and passed as pointer across controllers. tnqn#1 (comment)
No description provided.