diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 26b63b738..b5dc53648 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -2,9 +2,13 @@ name: Makefile CI on: push: - branches: [ main ] + branches: + - main + - 'v[0-9].[0-9]+.[0-9]+' pull_request: - branches: [ main ] + branches: + - main + - 'v[0-9].[0-9]+.[0-9]+' jobs: build: @@ -26,3 +30,11 @@ jobs: - name: Run test run: make test + + - name: Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./.coverage/coverage-unit.out + flags: unit-tests + name: codecov-unit-test diff --git a/.golangci.yml b/.golangci.yml index 973bd9662..c8d26644d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,6 +2,9 @@ run: tests: true timeout: 15m + skip-files: + - third_party/ + - pkg/client/ skip-dirs-use-default: true linters-settings: @@ -29,4 +32,10 @@ linters: - gosec - goimports - vet - - revive \ No newline at end of file + - revive + +issues: + exclude-rules: + - linters: + - staticcheck + text: "SA1019: lbs.RelaxScaleValidation" \ No newline at end of file diff --git a/Makefile b/Makefile index 8d98317e6..7fe1380c2 100644 --- a/Makefile +++ b/Makefile @@ -41,11 +41,12 @@ help: ## Display this help. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1;github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" output:crd:artifacts:config=build/yaml/crd/ + $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" output:crd:artifacts:config=build/yaml/crd/legacy/ + $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" output:crd:artifacts:config=build/yaml/crd/vpc/ .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. - $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./pkg/apis/..." .PHONY: fmt fmt: ## Run go fmt against code. @@ -78,7 +79,7 @@ golangci-fix: $(GOLANGCI_LINT_BIN) .PHONY: test test: manifests generate fmt vet envtest .coverage ## Run tests . - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -gcflags=all=-l ./... -coverprofile $(CURDIR)/.coverage/coverage-unit.out ## Prohibit inline optimization when using gomonkey + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -gcflags=all=-l ./... -v -coverprofile $(CURDIR)/.coverage/coverage-unit.out ## Prohibit inline optimization when using gomonkey ##@ Build @@ -86,6 +87,7 @@ test: manifests generate fmt vet envtest .coverage ## Run tests . build: generate fmt vet ## Build manager binary. @mkdir -p $(BINDIR) GOOS=linux go build -o $(BINDIR)/manager $(GOFLAGS) -ldflags '$(LDFLAGS)' cmd/main.go + GOOS=linux go build -o $(BINDIR)/webhookcert $(GOFLAGS) -ldflags '$(LDFLAGS)' cmd/webhookcert/main.go .PHONY: build-clean build-clean: generate fmt vet ## Build clean binary. @@ -145,14 +147,18 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi CONTROLLER_GEN = $(shell pwd)/bin/controller-gen .PHONY: controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.0) + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0) KUSTOMIZE = $(shell pwd)/bin/kustomize .PHONY: kustomize kustomize: ## Download kustomize locally if necessary. $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7) -generated: +.PHONY: code-generator +code-generator: ## Download code-generator locally if necessary. + go mod download k8s.io/code-generator@v0.27.1 + +generated: code-generator ./hack/update-codegen.sh ENVTEST = $(shell pwd)/bin/setup-envtest diff --git a/build/image/photon/Dockerfile b/build/image/photon/Dockerfile index 9d0072b2e..9926ed12b 100644 --- a/build/image/photon/Dockerfile +++ b/build/image/photon/Dockerfile @@ -1,9 +1,10 @@ -FROM golang:1.21.9 as golang-build +FROM golang:1.22.5 as golang-build WORKDIR /source COPY . /source RUN CGO_ENABLED=0 go build -o manager cmd/main.go +RUN CGO_ENABLED=0 go build -o webhookcert cmd/webhookcert/main.go RUN CGO_ENABLED=0 go build -o clean cmd_clean/main.go FROM photon @@ -12,6 +13,7 @@ RUN tdnf -y install shadow && \ useradd -s /bin/bash nsx-operator COPY --from=golang-build /source/manager /usr/local/bin/ +COPY --from=golang-build /source/webhookcert /usr/local/bin/ COPY --from=golang-build /source/clean /usr/local/bin/ USER nsx-operator diff --git a/build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml b/build/yaml/crd/legacy/nsx.vmware.com_nsxserviceaccounts.yaml similarity index 54% rename from build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml rename to build/yaml/crd/legacy/nsx.vmware.com_nsxserviceaccounts.yaml index 050ca15c3..b29d33835 100644 --- a/build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml +++ b/build/yaml/crd/legacy/nsx.vmware.com_nsxserviceaccounts.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: nsxserviceaccounts.nsx.vmware.com spec: group: nsx.vmware.com @@ -21,14 +20,19 @@ spec: description: NSXServiceAccount is the Schema for the nsxserviceaccounts API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -50,46 +54,47 @@ spec: clusterName: type: string conditions: - description: 'Represents the realization status of a NSXServiceAccount''s - current state. Known .status.conditions.type is: "Realized"' + description: |- + Represents the realization status of a NSXServiceAccount's current state. + Known .status.conditions.type is: "Realized" items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -103,11 +108,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/build/yaml/crd/nsx.vmware.com_securitypolicies.yaml b/build/yaml/crd/legacy/nsx.vmware.com_securitypolicies.yaml similarity index 58% rename from build/yaml/crd/nsx.vmware.com_securitypolicies.yaml rename to build/yaml/crd/legacy/nsx.vmware.com_securitypolicies.yaml index 188b90a70..d3a917663 100644 --- a/build/yaml/crd/nsx.vmware.com_securitypolicies.yaml +++ b/build/yaml/crd/legacy/nsx.vmware.com_securitypolicies.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: securitypolicies.nsx.vmware.com spec: group: nsx.vmware.com @@ -21,14 +20,19 @@ spec: description: SecurityPolicy is the Schema for the securitypolicies API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -36,7 +40,8 @@ spec: description: SecurityPolicySpec defines the desired state of SecurityPolicy. properties: appliedTo: - description: AppliedTo is a list of policy targets to apply rules. + description: |- + AppliedTo is a list of policy targets to apply rules. Policy level 'Applied To' will take precedence over rule level. items: description: SecurityPolicyTarget defines the target endpoints to @@ -49,41 +54,42 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -94,41 +100,42 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -149,8 +156,9 @@ spec: rule. type: string appliedTo: - description: AppliedTo is a list of rule targets. Policy level - 'Applied To' will take precedence over rule level. + description: |- + AppliedTo is a list of rule targets. + Policy level 'Applied To' will take precedence over rule level. items: description: SecurityPolicyTarget defines the target endpoints to apply SecurityPolicy. @@ -163,8 +171,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -172,33 +180,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -210,8 +218,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -219,33 +227,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -266,8 +274,9 @@ spec: by an AppliedTo. properties: cidr: - description: CIDR is a string representing the IP - Block. A valid example is "192.168.1.1/24". + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". type: string required: - cidr @@ -281,8 +290,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -290,33 +299,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -328,8 +337,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -337,33 +346,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -375,8 +384,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -384,33 +393,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -440,8 +449,9 @@ spec: x-kubernetes-int-or-string: true protocol: default: TCP - description: Protocol(TCP, UDP) is the protocol to match - traffic. It is TCP by default. + description: |- + Protocol(TCP, UDP) is the protocol to match traffic. + It is TCP by default. type: string type: object type: array @@ -460,8 +470,9 @@ spec: by an AppliedTo. properties: cidr: - description: CIDR is a string representing the IP - Block. A valid example is "192.168.1.1/24". + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". type: string required: - cidr @@ -475,8 +486,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -484,33 +495,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -522,8 +533,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -531,33 +542,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -569,8 +580,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -578,33 +589,33 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -625,10 +636,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_ippools.yaml b/build/yaml/crd/nsx.vmware.com_ippools.yaml deleted file mode 100644 index e6cf505c4..000000000 --- a/build/yaml/crd/nsx.vmware.com_ippools.yaml +++ /dev/null @@ -1,240 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: ippools.nsx.vmware.com -spec: - group: nsx.vmware.com - names: - kind: IPPool - listKind: IPPoolList - plural: ippools - singular: ippool - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: IPPool is the Schema for the ippools API. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: IPPoolSpec defines the desired state of IPPool. - properties: - subnets: - description: Subnets defines set of subnets need to be allocated. - items: - description: SubnetRequest defines the subnet allocation request. - properties: - ipFamily: - default: IPv4 - description: IPFamily defines the IP family type for this subnet, - could be IPv4 or IPv6. This is optional, the default is IPv4. - enum: - - IPv4 - - IPv6 - type: string - name: - description: Name defines the name of this subnet. - type: string - prefixLength: - description: PrefixLength defines prefix length for this subnet. - type: integer - required: - - name - type: object - type: array - type: object - status: - description: IPPoolStatus defines the observed state of IPPool. - properties: - conditions: - description: Conditions defines current state of the IPPool. - items: - description: Condition defines condition of custom resource. - properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. - format: date-time - type: string - message: - description: Message shows a human-readable message about condition. - type: string - reason: - description: Reason shows a brief reason of condition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type defines condition type. - type: string - required: - - status - - type - type: object - type: array - subnets: - description: Subnets defines subnets allocation result. - items: - description: SubnetResult defines the subnet allocation result. - properties: - cidr: - description: CIDR defines the allocated CIDR. - type: string - name: - description: Name defines the name of this subnet. - type: string - required: - - cidr - - name - type: object - type: array - required: - - conditions - - subnets - type: object - required: - - metadata - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - description: Type of IPPool - jsonPath: .spec.type - name: Type - type: string - - description: CIDRs for the Subnet - jsonPath: .status.subnets[*].cidr - name: Subnets - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - description: IPPool is the Schema for the ippools API. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: IPPoolSpec defines the desired state of IPPool. - properties: - subnets: - description: Subnets defines set of subnets need to be allocated. - items: - description: SubnetRequest defines the subnet allocation request. - properties: - ipFamily: - default: IPv4 - description: IPFamily defines the IP family type for this subnet, - could be IPv4 or IPv6. This is optional, the default is IPv4. - enum: - - IPv4 - - IPv6 - type: string - name: - description: Name defines the name of this subnet. - type: string - prefixLength: - description: PrefixLength defines prefix length for this subnet. - type: integer - required: - - name - type: object - type: array - type: - description: Type defines the type of this IPPool, Public or Private. - enum: - - Public - - Private - type: string - type: object - status: - description: IPPoolStatus defines the observed state of IPPool. - properties: - conditions: - description: Conditions defines current state of the IPPool. - items: - description: Condition defines condition of custom resource. - properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. - format: date-time - type: string - message: - description: Message shows a human-readable message about condition. - type: string - reason: - description: Reason shows a brief reason of condition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type defines condition type. - type: string - required: - - status - - type - type: object - type: array - subnets: - description: Subnets defines subnets allocation result. - items: - description: SubnetResult defines the subnet allocation result. - properties: - cidr: - description: CIDR defines the allocated CIDR. - type: string - name: - description: Name defines the name of this subnet. - type: string - required: - - cidr - - name - type: object - type: array - required: - - conditions - - subnets - type: object - required: - - metadata - - spec - type: object - served: true - storage: true - subresources: - status: {} diff --git a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml deleted file mode 100644 index 23b96a849..000000000 --- a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml +++ /dev/null @@ -1,124 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: vpcnetworkconfigurations.nsx.vmware.com -spec: - group: nsx.vmware.com - names: - kind: VPCNetworkConfiguration - listKind: VPCNetworkConfigurationList - plural: vpcnetworkconfigurations - singular: vpcnetworkconfiguration - scope: Cluster - versions: - - additionalPrinterColumns: - - description: NSXTProject the Namespace associated with - jsonPath: .spec.nsxtProject - name: NSXTProject - type: string - - description: ExternalIPv4Blocks assigned to the Namespace - jsonPath: .spec.externalIPv4Blocks - name: ExternalIPv4Blocks - type: string - - description: PrivateIPv4CIDRs assigned to the Namespace - jsonPath: .spec.privateIPv4CIDRs - name: PrivateIPv4CIDRs - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations - API. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: VPCNetworkConfigurationSpec defines the desired state of - VPCNetworkConfiguration. There is a default VPCNetworkConfiguration - that applies to Namespaces do not have a VPCNetworkConfiguration assigned. - When a field is not set in a Namespace's VPCNetworkConfiguration, the - Namespace will use the value in the default VPCNetworkConfiguration. - properties: - defaultGatewayPath: - description: PolicyPath of Tier0 or Tier0 VRF gateway. - type: string - defaultIPv4SubnetSize: - default: 26 - description: Default size of Subnet based upon estimated workload - count. Defaults to 26. - type: integer - defaultSubnetAccessMode: - description: DefaultSubnetAccessMode defines the access mode of the - default SubnetSet for PodVM and VM. Must be Public or Private. - enum: - - Public - - Private - type: string - edgeClusterPath: - description: Edge cluster path on which the networking elements will - be created. - type: string - externalIPv4Blocks: - description: NSX-T IPv4 Block paths used to allocate external Subnets. - items: - type: string - maxItems: 5 - minItems: 0 - type: array - nsxtProject: - description: NSX-T Project the Namespace associated with. - type: string - privateIPv4CIDRs: - description: Private IPv4 CIDRs used to allocate Private Subnets. - items: - type: string - maxItems: 5 - minItems: 0 - type: array - shortID: - description: ShortID specifies Identifier to use when displaying VPC - context in logs. Less than or equal to 8 characters. - maxLength: 8 - type: string - type: object - status: - description: VPCNetworkConfigurationStatus defines the observed state - of VPCNetworkConfiguration - properties: - vpcs: - description: VPCs describes VPC info, now it includes lb Subnet info - which are needed for AKO. - items: - description: VPCInfo defines VPC info needed by tenant admin. - properties: - lbSubnetPath: - description: AVISESubnetPath is the NSX Policy Path for the - AVI SE Subnet. - type: string - name: - description: VPC name. - type: string - required: - - name - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/build/yaml/crd/nsx.vmware.com_vpcs.yaml b/build/yaml/crd/nsx.vmware.com_vpcs.yaml deleted file mode 100644 index 4770ab615..000000000 --- a/build/yaml/crd/nsx.vmware.com_vpcs.yaml +++ /dev/null @@ -1,111 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: vpcs.nsx.vmware.com -spec: - group: nsx.vmware.com - names: - kind: VPC - listKind: VPCList - plural: vpcs - singular: vpc - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: Private IPv4 CIDRs - jsonPath: .status.privateIPv4CIDRs - name: PrivateIPv4CIDRs - type: string - - description: Default SNAT IP for Private Subnets - jsonPath: .status.defaultSNATIP - name: SNATIP - type: string - - description: CIDR for the load balancer Subnet - jsonPath: .status.lbSubnetCIDR - name: LBSubnetCIDR - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: VPC is the Schema for the VPC API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: VPCSpec defines VPC configuration - type: object - status: - description: VPCStatus defines the observed state of VPC - properties: - conditions: - items: - description: Condition defines condition of custom resource. - properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. - format: date-time - type: string - message: - description: Message shows a human-readable message about condition. - type: string - reason: - description: Reason shows a brief reason of condition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type defines condition type. - type: string - required: - - status - - type - type: object - type: array - defaultSNATIP: - description: Default SNAT IP for Private Subnets. - type: string - lbSubnetCIDR: - description: CIDR for the load balancer Subnet. - type: string - lbSubnetPath: - description: NSX PolicyPath for the load balancer Subnet. - type: string - nsxResourcePath: - description: NSX VPC Policy API resource path. - type: string - privateIPv4CIDRs: - description: Private CIDRs used for the VPC. - items: - type: string - type: array - required: - - conditions - - defaultSNATIP - - lbSubnetCIDR - - lbSubnetPath - - nsxResourcePath - - privateIPv4CIDRs - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_addressbindings.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_addressbindings.yaml new file mode 100644 index 000000000..a37d751ba --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_addressbindings.yaml @@ -0,0 +1,64 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: addressbindings.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: AddressBinding + listKind: AddressBindingList + plural: addressbindings + singular: addressbinding + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AddressBinding is used to manage 1:1 NAT for a VM/NetworkInterface. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + interfaceName: + description: InterfaceName contains the interface name of the VM, + if not set, the first interface of the VM will be used + type: string + vmName: + description: VMName contains the VM's name + type: string + required: + - vmName + type: object + status: + properties: + ipAddress: + type: string + required: + - ipAddress + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml new file mode 100644 index 000000000..9e478bd71 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml @@ -0,0 +1,110 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ipaddressallocations.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: IPAddressAllocation + listKind: IPAddressAllocationList + plural: ipaddressallocations + singular: ipaddressallocation + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: IPAddressBlockVisibility of IPAddressAllocation + jsonPath: .spec.ipAddressBlockVisibility + name: IPAddressBlockVisibility + type: string + - description: AllocationIPs for the IPAddressAllocation + jsonPath: .status.allocationIPs + name: AllocationIPs + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: IPAddressAllocation is the Schema for the IP allocation API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IPAddressAllocationSpec defines the desired state of IPAddressAllocation. + properties: + allocationSize: + description: AllocationSize specifies the size of allocationIPs to + be allocated. + type: integer + ipAddressBlockVisibility: + default: Private + description: IPAddressBlockVisibility specifies the visibility of + the IPBlocks to allocate IP addresses. Can be External, Private + or PrivateTGW. + enum: + - External + - Private + - PrivateTGW + type: string + type: object + status: + description: IPAddressAllocationStatus defines the observed state of IPAddressAllocation. + properties: + allocationIPs: + description: AllocationIPs is the allocated IP addresses + type: string + conditions: + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + required: + - allocationIPs + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_ipblocksinfos.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_ipblocksinfos.yaml new file mode 100644 index 000000000..c7ef5d438 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_ipblocksinfos.yaml @@ -0,0 +1,57 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ipblocksinfos.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: IPBlocksInfo + listKind: IPBlocksInfoList + plural: ipblocksinfos + singular: ipblocksinfo + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IPBlocksInfo is the Schema for the ipblocksinfo API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + externalIPCIDRs: + description: |- + ExternalIPCIDRs is a list of CIDR strings. Each CIDR is a contiguous IP address + spaces represented by network address and prefix length. The visibility of the + IPBlocks is External. + items: + type: string + type: array + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + privateTGWIPCIDRs: + description: |- + PrivateTGWIPCIDRs is a list of CIDR strings. Each CIDR is a contiguous IP address + spaces represented by network address and prefix length. The visibility of the + IPBlocks is PrivateTWG. Only IPBlocks in default project will be included. + items: + type: string + type: array + type: object + served: true + storage: true diff --git a/build/yaml/crd/nsx.vmware.com_networkinfoes.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml similarity index 62% rename from build/yaml/crd/nsx.vmware.com_networkinfoes.yaml rename to build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml index d5645079d..ab5db9b83 100644 --- a/build/yaml/crd/nsx.vmware.com_networkinfoes.yaml +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml @@ -3,15 +3,14 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: networkinfoes.nsx.vmware.com + controller-gen.kubebuilder.io/version: v0.14.0 + name: networkinfos.crd.nsx.vmware.com spec: - group: nsx.vmware.com + group: crd.nsx.vmware.com names: kind: NetworkInfo listKind: NetworkInfoList - plural: networkinfoes + plural: networkinfos singular: networkinfo scope: Namespaced versions: @@ -21,14 +20,19 @@ spec: description: NetworkInfo is used to report the network information for a namespace. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -46,7 +50,7 @@ spec: name: description: VPC name. type: string - privateIPv4CIDRs: + privateIPs: description: Private CIDRs used for the VPC. items: type: string @@ -57,7 +61,6 @@ spec: required: - defaultSNATIP - name - - vpcPath type: object type: array required: diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml new file mode 100644 index 000000000..87cc9824a --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml @@ -0,0 +1,671 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: securitypolicies.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: SecurityPolicy + listKind: SecurityPolicyList + plural: securitypolicies + singular: securitypolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: SecurityPolicy is the Schema for the securitypolicies API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SecurityPolicySpec defines the desired state of SecurityPolicy. + properties: + appliedTo: + description: |- + AppliedTo is a list of policy targets to apply rules. + Policy level 'Applied To' will take precedence over rule level. + items: + description: SecurityPolicyTarget defines the target endpoints to + apply SecurityPolicy. + properties: + podSelector: + description: PodSelector uses label selector to select Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + priority: + description: Priority defines the order of policy enforcement. + maximum: 1000 + minimum: 0 + type: integer + rules: + description: Rules is a list of policy rules. + items: + description: SecurityPolicyRule defines a rule of SecurityPolicy. + properties: + action: + description: Action specifies the action to be applied on the + rule. + type: string + appliedTo: + description: |- + AppliedTo is a list of rule targets. + Policy level 'Applied To' will take precedence over rule level. + items: + description: SecurityPolicyTarget defines the target endpoints + to apply SecurityPolicy. + properties: + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + destinations: + description: Destinations defines the endpoints where the traffic + is to. For egress rule only. + items: + description: SecurityPolicyPeer defines the source or destination + of traffic. + properties: + ipBlocks: + description: IPBlocks is a list of IP CIDRs. + items: + description: IPBlock describes a particular CIDR that + is allowed or denied to/from the workloads matched + by an AppliedTo. + properties: + cidr: + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". + type: string + required: + - cidr + type: object + type: array + namespaceSelector: + description: NamespaceSelector uses label selector to + select Namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + direction: + description: Direction is the direction of the rule, including + 'In' or 'Ingress', 'Out' or 'Egress'. + type: string + name: + description: Name is the display name of this rule. + type: string + ports: + description: Ports is a list of ports to be matched. + items: + description: SecurityPolicyPort describes protocol and ports + for traffic. + properties: + endPort: + description: EndPort defines the end of port range. + type: integer + port: + anyOf: + - type: integer + - type: string + description: Port is the name or port number. + x-kubernetes-int-or-string: true + protocol: + default: TCP + description: |- + Protocol(TCP, UDP) is the protocol to match traffic. + It is TCP by default. + type: string + type: object + type: array + sources: + description: Sources defines the endpoints where the traffic + is from. For ingress rule only. + items: + description: SecurityPolicyPeer defines the source or destination + of traffic. + properties: + ipBlocks: + description: IPBlocks is a list of IP CIDRs. + items: + description: IPBlock describes a particular CIDR that + is allowed or denied to/from the workloads matched + by an AppliedTo. + properties: + cidr: + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". + type: string + required: + - cidr + type: object + type: array + namespaceSelector: + description: NamespaceSelector uses label selector to + select Namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + required: + - action + - direction + type: object + type: array + type: object + status: + description: SecurityPolicyStatus defines the observed state of SecurityPolicy. + properties: + conditions: + description: Conditions describes current state of security policy. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/nsx.vmware.com_staticroutes.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml similarity index 70% rename from build/yaml/crd/nsx.vmware.com_staticroutes.yaml rename to build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml index b53ef56e7..40b106572 100644 --- a/build/yaml/crd/nsx.vmware.com_staticroutes.yaml +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml @@ -3,11 +3,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: staticroutes.nsx.vmware.com + controller-gen.kubebuilder.io/version: v0.14.0 + name: staticroutes.crd.nsx.vmware.com spec: - group: nsx.vmware.com + group: crd.nsx.vmware.com names: kind: StaticRoute listKind: StaticRouteList @@ -30,14 +29,19 @@ spec: description: StaticRoute is the Schema for the staticroutes API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -74,10 +78,10 @@ spec: description: StaticRouteCondition defines condition of StaticRoute. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: @@ -97,11 +101,8 @@ spec: - type type: object type: array - nsxResourcePath: - type: string required: - conditions - - nsxResourcePath type: object type: object served: true diff --git a/build/yaml/crd/nsx.vmware.com_subnetports.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml similarity index 74% rename from build/yaml/crd/nsx.vmware.com_subnetports.yaml rename to build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml index 60e241516..3737aa586 100644 --- a/build/yaml/crd/nsx.vmware.com_subnetports.yaml +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml @@ -3,11 +3,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: subnetports.nsx.vmware.com + controller-gen.kubebuilder.io/version: v0.14.0 + name: subnetports.crd.nsx.vmware.com spec: - group: nsx.vmware.com + group: crd.nsx.vmware.com names: kind: SubnetPort listKind: SubnetPortList @@ -34,14 +33,19 @@ spec: description: SubnetPort is the Schema for the subnetports API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -70,10 +74,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_subnets.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml similarity index 50% rename from build/yaml/crd/nsx.vmware.com_subnets.yaml rename to build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml index 7d5de517b..f497383dc 100644 --- a/build/yaml/crd/nsx.vmware.com_subnets.yaml +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml @@ -3,11 +3,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: subnets.nsx.vmware.com + controller-gen.kubebuilder.io/version: v0.14.0 + name: subnets.crd.nsx.vmware.com spec: - group: nsx.vmware.com + group: crd.nsx.vmware.com names: kind: Subnet listKind: SubnetList @@ -25,8 +24,8 @@ spec: name: IPv4SubnetSize type: string - description: CIDRs for the Subnet - jsonPath: .status.ipAddresses[*] - name: IPAddresses + jsonPath: .status.networkAddresses[*] + name: NetworkAddresses type: string name: v1alpha1 schema: @@ -34,14 +33,19 @@ spec: description: Subnet is the Schema for the subnets API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -51,30 +55,6 @@ spec: DHCPConfig: description: DHCPConfig DHCP configuration. properties: - dhcpRelayConfigPath: - description: DHCPRelayConfigPath is policy path of DHCP-relay-config. - type: string - dhcpV4PoolSize: - default: 80 - description: DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - By default, 80% of IPv4 IPs will be reserved for DHCP. Configure - 0 if no pool is required. - maximum: 100 - minimum: 0 - type: integer - dhcpV6PoolSize: - default: 2000 - description: DHCPV6PoolSize number of IPs to be reserved for DHCP - ranges. By default, 2000 IPv6 IPs will be reserved for DHCP. - type: integer - dnsClientConfig: - description: DNSClientConfig holds DNS configurations. - properties: - dnsServersIPs: - items: - type: string - type: array - type: object enableDHCP: default: false type: boolean @@ -85,21 +65,11 @@ spec: enum: - Private - Public + - PrivateTGW type: string - advancedConfig: - description: Subnet advanced configuration. - properties: - staticIPAllocation: - description: StaticIPAllocation configuration for subnet ports - with VIF attachment. - properties: - enable: - default: false - description: Enable or disable static IP allocation for subnet - ports with VIF attachment. - type: boolean - type: object - type: object + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf ipAddresses: description: Subnet CIDRS. items: @@ -116,15 +86,19 @@ spec: status: description: SubnetStatus defines the observed state of Subnet. properties: + DHCPServerAddresses: + items: + type: string + type: array conditions: items: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: @@ -144,12 +118,14 @@ spec: - type type: object type: array - ipAddresses: + gatewayAddresses: + items: + type: string + type: array + networkAddresses: items: type: string type: array - nsxResourcePath: - type: string type: object type: object served: true diff --git a/build/yaml/crd/nsx.vmware.com_subnetsets.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml similarity index 50% rename from build/yaml/crd/nsx.vmware.com_subnetsets.yaml rename to build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml index aac120f98..cd6a55c52 100644 --- a/build/yaml/crd/nsx.vmware.com_subnetsets.yaml +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml @@ -3,11 +3,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null - name: subnetsets.nsx.vmware.com + controller-gen.kubebuilder.io/version: v0.14.0 + name: subnetsets.crd.nsx.vmware.com spec: - group: nsx.vmware.com + group: crd.nsx.vmware.com names: kind: SubnetSet listKind: SubnetSetList @@ -24,9 +23,9 @@ spec: jsonPath: .spec.ipv4SubnetSize name: IPv4SubnetSize type: string - - description: CIDRs for the Subnet - jsonPath: .status.subnets[*].ipAddresses[*] - name: IPAddresses + - description: CIDRs for the SubnetSet + jsonPath: .status.subnets[*].networkAddresses[*] + name: NetworkAddresses type: string name: v1alpha1 schema: @@ -34,14 +33,19 @@ spec: description: SubnetSet is the Schema for the subnetsets API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -51,30 +55,6 @@ spec: DHCPConfig: description: DHCPConfig DHCP configuration. properties: - dhcpRelayConfigPath: - description: DHCPRelayConfigPath is policy path of DHCP-relay-config. - type: string - dhcpV4PoolSize: - default: 80 - description: DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - By default, 80% of IPv4 IPs will be reserved for DHCP. Configure - 0 if no pool is required. - maximum: 100 - minimum: 0 - type: integer - dhcpV6PoolSize: - default: 2000 - description: DHCPV6PoolSize number of IPs to be reserved for DHCP - ranges. By default, 2000 IPv6 IPs will be reserved for DHCP. - type: integer - dnsClientConfig: - description: DNSClientConfig holds DNS configurations. - properties: - dnsServersIPs: - items: - type: string - type: array - type: object enableDHCP: default: false type: boolean @@ -85,21 +65,11 @@ spec: enum: - Private - Public + - PrivateTGW type: string - advancedConfig: - description: Subnet advanced configuration. - properties: - staticIPAllocation: - description: StaticIPAllocation configuration for subnet ports - with VIF attachment. - properties: - enable: - default: false - description: Enable or disable static IP allocation for subnet - ports with VIF attachment. - type: boolean - type: object - type: object + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf ipv4SubnetSize: description: Size of Subnet based upon estimated workload count. maximum: 65536 @@ -114,10 +84,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: @@ -142,15 +112,18 @@ spec: description: SubnetInfo defines the observed state of a single Subnet of a SubnetSet. properties: - ipAddresses: + DHCPServerAddresses: + items: + type: string + type: array + gatewayAddresses: + items: + type: string + type: array + networkAddresses: items: type: string type: array - nsxResourcePath: - type: string - required: - - ipAddresses - - nsxResourcePath type: object type: array type: object diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml new file mode 100644 index 000000000..54df1b798 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml @@ -0,0 +1,147 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: vpcnetworkconfigurations.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: VPCNetworkConfiguration + listKind: VPCNetworkConfigurationList + plural: vpcnetworkconfigurations + singular: vpcnetworkconfiguration + scope: Cluster + versions: + - additionalPrinterColumns: + - description: NSXProject the Namespace associated with + jsonPath: .spec.nsxProject + name: NSXProject + type: string + - description: PrivateIPs assigned to the Namespace + jsonPath: .spec.privateIPs + name: PrivateIPs + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. + There is a default VPCNetworkConfiguration that applies to Namespaces + do not have a VPCNetworkConfiguration assigned. When a field is not set + in a Namespace's VPCNetworkConfiguration, the Namespace will use the value + in the default VPCNetworkConfiguration. + properties: + defaultSubnetSize: + default: 32 + description: |- + Default size of Subnets. + Defaults to 32. + maximum: 65536 + minimum: 16 + type: integer + nsxProject: + description: NSX Project the Namespace associated with. + type: string + privateIPs: + description: Private IPs. + items: + type: string + type: array + vpc: + description: |- + NSX path of the VPC the Namespace associated with. + If VPC is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + take effect, other fields are ignored. + type: string + vpcConnectivityProfile: + description: VPCConnectivityProfile ID. This profile has configuration + related to creating VPC transit gateway attachment. + type: string + type: object + status: + description: VPCNetworkConfigurationStatus defines the observed state + of VPCNetworkConfiguration + properties: + conditions: + description: Conditions describe current state of VPCNetworkConfiguration. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + vpcs: + description: VPCs describes VPC info, now it includes lb Subnet info + which are needed for AKO. + items: + description: VPCInfo defines VPC info needed by tenant admin. + properties: + lbSubnetPath: + description: AVISESubnetPath is the NSX Policy Path for the + AVI SE Subnet. + type: string + name: + description: VPC name. + type: string + nsxLoadBalancerPath: + description: NSXLoadBalancerPath is the NSX Policy path for + the NSX Load Balancer. + type: string + vpcPath: + description: NSX Policy path for VPC. + type: string + required: + - name + - vpcPath + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml b/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml new file mode 100644 index 000000000..90321c4fa --- /dev/null +++ b/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml @@ -0,0 +1,30 @@ +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: IPAddressAllocation +metadata: + name: guestcluster-workers-a + namespace: sc-a +spec: + ipAddressBlockVisibility: Private + allocationSize: 32 + + --- + +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: IPAddressAllocation +metadata: + name: guestcluster-workers-b + namespace: sc-a +spec: + ipAddressBlockVisibility: External + allocationSize: 32 + + --- + +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: IPAddressAllocation +metadata: + name: guestcluster-workers-c + namespace: sc-a +spec: + ipAddressBlockVisibility: PrivateTGW + allocationSize: 32 diff --git a/build/yaml/samples/nsx_v1alpha1_ipblocksinfo.yaml b/build/yaml/samples/nsx_v1alpha1_ipblocksinfo.yaml new file mode 100644 index 000000000..108a1196d --- /dev/null +++ b/build/yaml/samples/nsx_v1alpha1_ipblocksinfo.yaml @@ -0,0 +1,9 @@ +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: IPBlocksInfo +metadata: + name: ip-blocks-info +externalIPCIDRs: +- 192.168.0.0/16 +privateTGWIPCIDRs: +- 10.172.0.0/16 +- 10.173.0.0/16 diff --git a/build/yaml/samples/nsx_v1alpha1_networkinfo.yaml b/build/yaml/samples/nsx_v1alpha1_networkinfo.yaml new file mode 100644 index 000000000..1368d2e6a --- /dev/null +++ b/build/yaml/samples/nsx_v1alpha1_networkinfo.yaml @@ -0,0 +1,18 @@ +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: NetworkInfo +metadata: + creationTimestamp: "2024-05-14T02:14:18Z" + finalizers: + - networkinfo.crd.nsx.vmware.com/finalizer + generation: 2 + name: kube-system + namespace: kube-system + resourceVersion: "76701" + uid: 518c4acf-3f4b-4593-9115-68ef0d697908 +vpcs: +- defaultSNATIP: 192.168.0.0 + loadBalancerIPAddresses: 172.26.0.0/26 + name: vpc-d110d5aa-006d-4b59-9caf-424a4fba932c--kube-system + privateIPs: + - 172.26.0.0/16 + vpcPath: /orgs/default/projects/project-quality/vpcs/19a8a52e-beb0-4396-91ce-5821a15a43db \ No newline at end of file diff --git a/build/yaml/samples/nsx_v1alpha1_securitypolicy.yaml b/build/yaml/samples/nsx_v1alpha1_securitypolicy.yaml index a2a8be4bf..b20202987 100644 --- a/build/yaml/samples/nsx_v1alpha1_securitypolicy.yaml +++ b/build/yaml/samples/nsx_v1alpha1_securitypolicy.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: egress-policy-1 @@ -22,7 +22,7 @@ spec: --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: ingress-policy-1 diff --git a/build/yaml/samples/nsx_v1alpha1_staticroute.yaml b/build/yaml/samples/nsx_v1alpha1_staticroute.yaml index 704972ffe..244207691 100644 --- a/build/yaml/samples/nsx_v1alpha1_staticroute.yaml +++ b/build/yaml/samples/nsx_v1alpha1_staticroute.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: StaticRoute metadata: name: test-2 diff --git a/build/yaml/samples/nsx_v1alpha1_subnet.yaml b/build/yaml/samples/nsx_v1alpha1_subnet.yaml index 7cc93fa91..21c5e55e6 100644 --- a/build/yaml/samples/nsx_v1alpha1_subnet.yaml +++ b/build/yaml/samples/nsx_v1alpha1_subnet.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: Subnet metadata: name: subnet-sample diff --git a/build/yaml/samples/nsx_v1alpha1_subnetset.yaml b/build/yaml/samples/nsx_v1alpha1_subnetset.yaml index fb458d4cd..751d8ad5c 100644 --- a/build/yaml/samples/nsx_v1alpha1_subnetset.yaml +++ b/build/yaml/samples/nsx_v1alpha1_subnetset.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetSet metadata: name: subnetset-sample diff --git a/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml b/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml index c19703c2f..d7932b059 100644 --- a/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml +++ b/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml @@ -1,15 +1,20 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: VPCNetworkConfiguration metadata: name: vpc-network-config1 spec: - defaultGatewayPath: /infra/tier-0s/t0 - edgeClusterPath: /infra/sites/default/enforcement-points/default/edge-clusters/2d9df59f-6dc6-4911-8865-21fadc23d4da - defaultIPv4SubnetSize: 26 - nsxtProject: proj-1 - externalIPv4Blocks: - - block1 - privateIPv4CIDRs: + defaultSubnetSize: 32 + nsxProject: proj-1 + privateIPs: - 172.26.0.0/16 - 172.36.0.0/16 - defaultSubnetAccessMode: Private +--- +# Sample to create VPCNetworkConfiguration CR using a pre-created NSX VPC. +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: VPCNetworkConfiguration +metadata: + name: vpc-network-config-with-pre-created-vpc +spec: + vpc: /orgs/default/projects/proj-1/vpcs/vpc-1 + defaultSubnetSize: 32 + vpcConnectivityProfile: /orgs/default/projects/wenqi-test/vpc-connectivity-profiles/default diff --git a/build/yaml/samples/nsx_v1alpha1_vpcs.yaml b/build/yaml/samples/nsx_v1alpha1_vpcs.yaml deleted file mode 100644 index 99b9afc14..000000000 --- a/build/yaml/samples/nsx_v1alpha1_vpcs.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: nsx.vmware.com/v1alpha1 -kind: VPC -metadata: - name: vpc-default -spec: - diff --git a/build/yaml/samples/nsx_v1alpha2_ippool.yaml b/build/yaml/samples/nsx_v1alpha2_ippool.yaml deleted file mode 100644 index 41713643d..000000000 --- a/build/yaml/samples/nsx_v1alpha2_ippool.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: nsx.vmware.com/v1alpha2 -kind: IPPool -metadata: - name: guestcluster-ippool - namespace: sc-a -spec: - subnets: - - ipFamily: IPv4 - name: guestcluster1-workers-a - prefixLength: 26 - - ipFamily: IPv4 - name: guestcluster1-workers-b - prefixLength: 26 - - ipFamily: IPv4 - name: guestcluster1-workers-c - prefixLength: 26 \ No newline at end of file diff --git a/build/yaml/webhook/manifests.yaml b/build/yaml/webhook/manifests.yaml index 74ed035c8..71bc17b0b 100644 --- a/build/yaml/webhook/manifests.yaml +++ b/build/yaml/webhook/manifests.yaml @@ -3,9 +3,7 @@ apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: creationTimestamp: null - name: validating-webhook-configuration - annotations: - cert-manager.io/inject-ca-from: vmware-system-nsx/nsx-operator-webhook-cert + name: nsx-operator-validating-webhook-configuration webhooks: - admissionReviewVersions: - v1 diff --git a/cmd/main.go b/cmd/main.go index 2dde8d352..8a3fb352f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -16,17 +16,18 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/ipaddressallocation" "github.com/vmware-tanzu/nsx-operator/pkg/config" - ippool2 "github.com/vmware-tanzu/nsx-operator/pkg/controllers/ippool" namespacecontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/namespace" + networkinfocontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/networkinfo" networkpolicycontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/networkpolicy" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/node" - nsxserviceaccountcontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/nsxserviceaccount" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/pod" securitypolicycontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/securitypolicy" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/service" @@ -34,17 +35,19 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/controllers/subnet" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/subnetport" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/subnetset" - vpccontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/vpc" + nodeservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/node" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/staticroute" + subnetservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnet" + subnetportservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnetport" + + commonctl "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" + nsxserviceaccountcontroller "github.com/vmware-tanzu/nsx-operator/pkg/controllers/nsxserviceaccount" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/metrics" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ippool" - nodeservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/node" + ipaddressallocationservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/nsxserviceaccount" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/staticroute" - subnetservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnet" - subnetportservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnetport" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" ) @@ -59,8 +62,8 @@ var ( func init() { var err error utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(crdv1alpha1.AddToScheme(scheme)) utilruntime.Must(v1alpha1.AddToScheme(scheme)) - utilruntime.Must(v1alpha2.AddToScheme(scheme)) utilruntime.Must(vmv1alpha1.AddToScheme(scheme)) config.AddFlags() @@ -103,34 +106,21 @@ func StartNSXServiceAccountController(mgr ctrl.Manager, commonService common.Ser log.Error(err, "failed to create controller", "controller", "NSXServiceAccount") os.Exit(1) } + go commonctl.GenericGarbageCollector(make(chan bool), common.GCInterval, nsxServiceAccountReconcile.CollectGarbage) } -func StartIPPoolController(mgr ctrl.Manager, ipPoolService *ippool.IPPoolService, vpcService common.VPCServiceProvider) { - ippoolReconcile := &ippool2.IPPoolReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Service: ipPoolService, - VPCService: vpcService, - Recorder: mgr.GetEventRecorderFor("ippool-controller"), - } - - if err := ippoolReconcile.Start(mgr); err != nil { - log.Error(err, "failed to create controller", "controller", "IPPool") - os.Exit(1) - } -} - -func StartVPCController(mgr ctrl.Manager, vpcService *vpc.VPCService) { - vpcReconciler := &vpccontroller.VPCReconciler{ +func StartNetworkInfoController(mgr ctrl.Manager, vpcService *vpc.VPCService) { + networkInfoReconciler := &networkinfocontroller.NetworkInfoReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor("vpc-controller"), + Recorder: mgr.GetEventRecorderFor("networkinfo-controller"), } - vpcReconciler.Service = vpcService - if err := vpcReconciler.Start(mgr); err != nil { - log.Error(err, "failed to create vpc controller", "controller", "VPC") + networkInfoReconciler.Service = vpcService + if err := networkInfoReconciler.Start(mgr); err != nil { + log.Error(err, "failed to create networkinfo controller", "controller", "NetworkInfo") os.Exit(1) } + go commonctl.GenericGarbageCollector(make(chan bool), common.GCInterval, networkInfoReconciler.CollectGarbage) } func StartNamespaceController(mgr ctrl.Manager, cf *config.NSXOperatorConfig, vpcService common.VPCServiceProvider) { @@ -147,28 +137,23 @@ func StartNamespaceController(mgr ctrl.Manager, cf *config.NSXOperatorConfig, vp } } -func main() { - log.Info("starting NSX Operator") - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - HealthProbeBindAddress: config.ProbeAddr, - Metrics: metricsserver.Options{BindAddress: config.MetricsAddr}, - LeaderElection: cf.HAEnabled(), - LeaderElectionNamespace: nsxOperatorNamespace, - LeaderElectionID: "nsx-operator", - }) - if err != nil { - log.Error(err, "failed to init manager") - os.Exit(1) +func StartIPAddressAllocationController(mgr ctrl.Manager, ipAddressAllocationService *ipaddressallocationservice.IPAddressAllocationService, vpcService common.VPCServiceProvider) { + ipAddressAllocationReconciler := &ipaddressallocation.IPAddressAllocationReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Service: ipAddressAllocationService, + VPCService: vpcService, + Recorder: mgr.GetEventRecorderFor("ipaddressallocation-controller"), } - // nsxClient is used to interact with NSX API. - nsxClient := nsx.GetClient(cf) - if nsxClient == nil { - log.Error(err, "failed to get nsx client") + if err := ipAddressAllocationReconciler.SetupWithManager(mgr); err != nil { + log.Error(err, "failed to create ipaddressallocation controller") os.Exit(1) } + go commonctl.GenericGarbageCollector(make(chan bool), common.GCInterval, ipAddressAllocationReconciler.CollectGarbage) +} +func startServiceController(mgr manager.Manager, nsxClient *nsx.Client) { // Embed the common commonService to sub-services. commonService := common.Service{ Client: mgr.GetClient(), @@ -188,6 +173,7 @@ func main() { } log.Info("VPC mode is enabled") + var err error vpcService, err = vpc.InitializeVPC(commonService) if err != nil { log.Error(err, "failed to initialize vpc commonService", "controller", "VPC") @@ -198,9 +184,9 @@ func main() { log.Error(err, "failed to initialize subnet commonService") os.Exit(1) } - ipPoolService, err := ippool.InitializeIPPool(commonService, vpcService) + ipAddressAllocationService, err := ipaddressallocationservice.InitializeIPAddressAllocation(commonService, vpcService, false) if err != nil { - log.Error(err, "failed to initialize ippool commonService", "controller", "IPPool") + log.Error(err, "failed to initialize ipaddressallocation commonService", "controller", "IPAddressAllocation") } subnetPortService, err := subnetportservice.InitializeSubnetPort(commonService) if err != nil { @@ -218,7 +204,7 @@ func main() { os.Exit(1) } // Start controllers which only supports VPC - StartVPCController(mgr, vpcService) + StartNetworkInfoController(mgr, vpcService) StartNamespaceController(mgr, cf, vpcService) // Start subnet/subnetset controller. if err := subnet.StartSubnetController(mgr, subnetService, subnetPortService, vpcService); err != nil { @@ -237,7 +223,7 @@ func main() { staticroutecontroller.StartStaticRouteController(mgr, staticRouteService) subnetport.StartSubnetPortController(mgr, subnetPortService, subnetService, vpcService) pod.StartPodController(mgr, subnetPortService, subnetService, vpcService, nodeService) - StartIPPoolController(mgr, ipPoolService, vpcService) + StartIPAddressAllocationController(mgr, ipAddressAllocationService, vpcService) networkpolicycontroller.StartNetworkPolicyController(mgr, commonService, vpcService) service.StartServiceLbController(mgr, commonService) } @@ -249,6 +235,43 @@ func main() { StartNSXServiceAccountController(mgr, commonService) } +} + +func electMaster(mgr manager.Manager, nsxClient *nsx.Client) { + log.Info("I'm trying to be elected as master") + <-mgr.Elected() + log.Info("I'm the master now") + startServiceController(mgr, nsxClient) +} + +func main() { + log.Info("starting NSX Operator") + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + HealthProbeBindAddress: config.ProbeAddr, + Metrics: metricsserver.Options{BindAddress: config.MetricsAddr}, + LeaderElection: cf.HAEnabled(), + LeaderElectionNamespace: nsxOperatorNamespace, + LeaderElectionID: "nsx-operator", + }) + if err != nil { + log.Error(err, "failed to init manager") + os.Exit(1) + } + + // nsxClient is used to interact with NSX API. + nsxClient := nsx.GetClient(cf) + if nsxClient == nil { + log.Error(nil, "failed to get nsx client") + os.Exit(1) + } + + if cf.HAEnabled() { + go electMaster(mgr, nsxClient) + } else { + startServiceController(mgr, nsxClient) + } + if metrics.AreMetricsExposed(cf) { go updateHealthMetricsPeriodically(nsxClient) } diff --git a/cmd/webhookcert/main.go b/cmd/webhookcert/main.go new file mode 100644 index 000000000..e2ac603c8 --- /dev/null +++ b/cmd/webhookcert/main.go @@ -0,0 +1,224 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package main + +import ( + "bytes" + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "os" + "path" + "time" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/vmware-tanzu/nsx-operator/pkg/config" + "github.com/vmware-tanzu/nsx-operator/pkg/logger" +) + +var ( + log = logger.Log + validatingWebhookConfiguration = "nsx-operator-validating-webhook-configuration" + namespace = "vmware-system-nsx" + certName = "nsx-operator-webhook-cert" +) + +func main() { + log.Info("Generating webhook certificates...") + if err := generateWebhookCerts(); err != nil { + panic(err) + } +} + +// WriteFile writes data in the file at the given path +func writeFile(filepath string, cert []byte) error { + f, err := os.Create(filepath) + if err != nil { + return err + } + defer f.Close() + + _, err = f.Write(cert) + if err != nil { + return err + } + return nil +} + +func generateWebhookCerts() error { + var caPEM, serverCertPEM, serverKeyPEM *bytes.Buffer + // CA config + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return err + } + ca := &x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"broadcom.com"}, + CommonName: "webhook", + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + // CA private key + caKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + log.Error(err, "Failed to generate private key") + return err + } + + // Self-signed CA certificate + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caKey.PublicKey, caKey) + if err != nil { + log.Error(err, "Failed to generate CA") + return err + } + + // PEM encode CA cert + caPEM = new(bytes.Buffer) + pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }) + + dnsNames := []string{"subnetset", "subnetset.vmware-system-nsx", "subnetset.vmware-system-nsx.svc"} + commonName := "subnetset.vmware-system-nsx.svc" + + serialNumber, err = rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return err + } + // server cert config + cert := &x509.Certificate{ + DNSNames: dnsNames, + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: commonName, + Organization: []string{"broadcom.com"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), + SubjectKeyId: []byte{1, 2, 3, 4, 6}, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature, + } + + // server private key + serverKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + log.Error(err, "Failed to generate server key") + return err + } + + // sign the server cert + serverCertBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, &serverKey.PublicKey, caKey) + if err != nil { + log.Error(err, "Failed to sign server certificate") + return err + } + + // PEM encode the server cert and key + serverCertPEM = new(bytes.Buffer) + pem.Encode(serverCertPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: serverCertBytes, + }) + + serverKeyPEM = new(bytes.Buffer) + pem.Encode(serverKeyPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(serverKey), + }) + + kubeClient := kubernetes.NewForConfigOrDie(ctrl.GetConfigOrDie()) + certSecret := &corev1.Secret{ + TypeMeta: v1.TypeMeta{}, + ObjectMeta: v1.ObjectMeta{ + Namespace: namespace, + Name: certName, + }, + Data: map[string][]byte{ + "tls.key": serverKeyPEM.Bytes(), + "tls.crt": serverCertPEM.Bytes(), + }, + } + if err := retry.OnError(retry.DefaultRetry, func(err error) bool { + return err != nil + }, func() error { + if _, err := kubeClient.CoreV1().Secrets(namespace).Create(context.TODO(), certSecret, v1.CreateOptions{}); err != nil { + if errors.IsAlreadyExists(err) { + // In HA mode, there are multiple nsx-operator instances trying to create webhook certificates, this + // guarantees that only one instance can create webhook certificates. + log.Info("Secret already existed, skip creating", "name", certName) + certSecret, err = kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), certName, v1.GetOptions{}) + if err != nil { + return err + } + } else { + log.Error(err, "Failed to create secret", "name", certName) + return err + } + } else { + if err = updateWebhookConfig(kubeClient, caPEM); err != nil { + log.Error(err, "Failed to update webhook configuration", "name", validatingWebhookConfiguration) + return err + } + } + return nil + }); err != nil { + return err + } + if err = os.MkdirAll(config.WebhookCertDir, 0755); err != nil { + log.Error(err, "Failed to create directory", "Dir", config.WebhookCertDir) + return err + } + if err = writeFile(path.Join(config.WebhookCertDir, "tls.crt"), certSecret.Data["tls.crt"]); err != nil { + log.Error(err, "Failed to write tls cert", "Path", path.Join(config.WebhookCertDir, "tls.crt")) + return err + } + + if err = writeFile(path.Join(config.WebhookCertDir, "tls.key"), certSecret.Data["tls.key"]); err != nil { + log.Error(err, "Failed to write tls cert", "Path", path.Join(config.WebhookCertDir, "tls.key")) + return err + } + return nil +} + +func updateWebhookConfig(kubeClient *kubernetes.Clientset, caCert *bytes.Buffer) error { + webhookCfg, err := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Get(context.TODO(), validatingWebhookConfiguration, v1.GetOptions{}) + if err != nil { + return err + } + updated := false + for idx, webhook := range webhookCfg.Webhooks { + if bytes.Equal(webhook.ClientConfig.CABundle, caCert.Bytes()) { + continue + } + updated = true + webhook.ClientConfig.CABundle = caCert.Bytes() + webhookCfg.Webhooks[idx] = webhook + } + if updated { + if _, err := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Update(context.TODO(), webhookCfg, v1.UpdateOptions{}); err != nil { + return err + } + } + return nil +} diff --git a/cmd_clean/main.go b/cmd_clean/main.go index cd3138515..26189b297 100644 --- a/cmd_clean/main.go +++ b/cmd_clean/main.go @@ -9,8 +9,6 @@ import ( "os" "time" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "github.com/vmware-tanzu/nsx-operator/pkg/clean" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -78,11 +76,10 @@ func main() { cf.EnvoyHost = envoyHost cf.EnvoyPort = envoyPort - logf.SetLogger(logger.ZapLogger(cf.DefaultConfig.Debug, config.LogLevel)) ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) defer cancel() - - err := clean.Clean(ctx, cf) + log = logger.ZapLogger(cf.DefaultConfig.Debug, config.LogLevel) + err := clean.Clean(ctx, cf, &log, cf.DefaultConfig.Debug, config.LogLevel) if err != nil { log.Error(err, "failed to clean nsx resources") os.Exit(1) diff --git a/codecov.yaml b/codecov.yaml new file mode 100644 index 000000000..d943e6e5f --- /dev/null +++ b/codecov.yaml @@ -0,0 +1,35 @@ +codecov: + branch: main + require_ci_to_pass: no + +comment: + layout: "reach,diff,flags,tree" + behavior: default + require_changes: no + require_base: no + require_head: no + after_n_builds: 1 + show_carryforward_flags: true + +github_checks: + annotations: true + +coverage: + status: + patch: + default: + target: 70% + threshold: 5% + base: auto + only_pulls: false + project: + default: + target: auto + threshold: 0.3% + +flag_management: + default_rules: + carryforward: true + +ignore: + - "**/testing/*.go" \ No newline at end of file diff --git a/go.mod b/go.mod index 0e56b783d..b0b7612d1 100644 --- a/go.mod +++ b/go.mod @@ -1,43 +1,50 @@ module github.com/vmware-tanzu/nsx-operator -go 1.21.9 +go 1.22.5 replace ( github.com/vmware-tanzu/nsx-operator/pkg/apis => ./pkg/apis + github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1 => ./pkg/apis/vpc/v1alpha1 + github.com/vmware-tanzu/nsx-operator/pkg/client => ./pkg/client + github.com/vmware/vsphere-automation-sdk-go/lib => github.com/zhengxiexie/vsphere-automation-sdk-go/lib v0.7.3-0.20240808083204-389375dc2535 + github.com/vmware/vsphere-automation-sdk-go/runtime => github.com/zhengxiexie/vsphere-automation-sdk-go/runtime v0.7.3-0.20240808083204-389375dc2535 + github.com/vmware/vsphere-automation-sdk-go/services/nsxt => github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt v0.12.3-0.20240808083204-389375dc2535 + github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp => github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt-mp v0.6.3-0.20240808083204-389375dc2535 ) require ( + github.com/agiledragon/gomonkey v2.0.2+incompatible github.com/agiledragon/gomonkey/v2 v2.9.0 github.com/apparentlymart/go-cidr v1.1.0 github.com/deckarep/golang-set v1.8.0 - github.com/go-logr/logr v1.3.0 + github.com/go-logr/logr v1.4.1 + github.com/go-logr/zapr v1.3.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/kevinburke/ssh_config v1.2.0 github.com/openlyinc/pointy v1.1.2 - github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.4 - github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240305035435-c992c623aad3 + github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240813023528-cb525458c6ee github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240102061654-537b080e159f github.com/vmware-tanzu/vm-operator/api v1.8.2 github.com/vmware/govmomi v0.27.4 github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0 - github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0 + github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.1-0.20240611083326-25a4e1834c4d github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.12.0 github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.6.0 go.uber.org/automaxprocs v1.5.3 - go.uber.org/zap v1.25.0 - golang.org/x/crypto v0.17.0 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.21.0 golang.org/x/time v0.3.0 gopkg.in/ini.v1 v1.66.4 - k8s.io/api v0.29.3 - k8s.io/apimachinery v0.29.3 - k8s.io/client-go v0.29.3 - k8s.io/code-generator v0.29.3 - sigs.k8s.io/controller-runtime v0.16.0 + k8s.io/api v0.30.3 + k8s.io/apimachinery v0.30.3 + k8s.io/client-go v0.30.3 + k8s.io/code-generator v0.30.1 + sigs.k8s.io/controller-runtime v0.18.4 ) require ( @@ -47,10 +54,9 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gibson042/canonicaljson-go v1.0.3 // indirect - github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -69,32 +75,32 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.16.1 // indirect + golang.org/x/tools v0.18.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.29.3 // indirect - k8s.io/component-base v0.29.3 // indirect - k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/apiextensions-apiserver v0.30.1 // indirect + k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index 9e76e1f43..48a97b43c 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,16 @@ -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/a8m/tree v0.0.0-20210115125333-10a5fd5b637d/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg= +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= github.com/agiledragon/gomonkey/v2 v2.9.0 h1:PDiKKybR596O6FHW+RVSG0Z7uGCBNbmbUXh3uCNQ7Hc= github.com/agiledragon/gomonkey/v2 v2.9.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= -github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -37,22 +22,16 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gibson042/canonicaljson-go v1.0.3 h1:EAyF8L74AWabkyUmrvEFHEt/AGFQeD6RfwbAuf0j1bI= github.com/gibson042/canonicaljson-go v1.0.3/go.mod h1:DsLpJTThXyGNO+KZlI85C1/KDcImpP67k/RKVjcaEqo= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -75,16 +54,12 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= -github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= @@ -93,16 +68,8 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -113,7 +80,6 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -132,13 +98,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= github.com/openlyinc/pointy v1.1.2 h1:LywVV2BWC5Sp5v7FoP4bUD+2Yn5k0VNeRbU5vq9jUMY= github.com/openlyinc/pointy v1.1.2/go.mod h1:w2Sytx+0FVuMKn37xpXIAyBNhFNBIJGR/v2m7ik1WtM= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -151,20 +116,16 @@ github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUo github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= @@ -177,75 +138,42 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240305035435-c992c623aad3 h1:zzmSSKDtJoyCsTVX8Py0U7NvmaqFyUpKUlKYejuBv8k= -github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240305035435-c992c623aad3/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk= -github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240102061654-537b080e159f h1:EV4eiUQr3QpUGfTtqdVph0+bmE+3cj0aNJpd9n2qTdo= -github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240102061654-537b080e159f/go.mod h1:dzob8tUzpAREQPtbbjQs4b1UyQDR37B2TiIdg8WJSRM= github.com/vmware-tanzu/vm-operator/api v1.8.2 h1:7cZHVusqAmAMFWvsiU7X5xontxdjasknI/sVfe0p0Z4= github.com/vmware-tanzu/vm-operator/api v1.8.2/go.mod h1:vauVboD3sQxP+pb28TnI9wfrj+0nH2zSEc9Q7AzWJ54= github.com/vmware/govmomi v0.27.4 h1:5kY8TAkhB20lsjzrjE073eRb8+HixBI29PVMG5lxq6I= github.com/vmware/govmomi v0.27.4/go.mod h1:daTuJEcQosNMXYJOeku0qdBJP9SOLLWB3Mqz8THtv6o= github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= -github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0 h1:pT+oqJ8FD5eUBQkl+e7LZwwtbwPvW5kDyyGXvt66gOM= -github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0/go.mod h1:f3+6YVZpNcK2pYyiQ94BoHWmjMj9BnYav0vNFuTiDVM= -github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0 h1:pSBxa9Agh6bgW8Hr0A1eQxuwnxGTnuAVox8iQb023hg= -github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0/go.mod h1:qdzEFm2iK3dvlmm99EYYNxs70HbzuiHyENFD24Ps8fQ= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.12.0 h1:+kcDO69bfIB87KZUAYQ4AqrXlnZhpZz+QwzIB+TseqU= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.12.0/go.mod h1:upLH9b9zpG86P0wwO4+gREf0lBXr8gYcs7P1FRZ9n30= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.6.0 h1:+jS0YH9dEp8rC00SsaY5feFpVgp4Lu0YBnBe3T7zfqo= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.6.0/go.mod h1:ugk9I4YM62SSAox57l5NAVBCRIkPQ1RNLb3URxyTADc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= -go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= -go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= -go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= -go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= -go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 h1:KfYpVmrjI7JuToy5k8XV3nkapjWx48k4E4JOtVstzQI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +github.com/zhengxiexie/vsphere-automation-sdk-go/lib v0.7.3-0.20240808083204-389375dc2535 h1:RyRlKXlQBsDuuhi9xNdW5ygh7P9LPD4VwohMFFktpNI= +github.com/zhengxiexie/vsphere-automation-sdk-go/lib v0.7.3-0.20240808083204-389375dc2535/go.mod h1:AEp9XK68cVmyxUtAYZekGBEauHwmMKCykLWOWkX7GII= +github.com/zhengxiexie/vsphere-automation-sdk-go/runtime v0.7.3-0.20240808083204-389375dc2535 h1:ACBksAqrTPfO38jfPYUYkPxLEmkRb1kAnaiDbn2b9mI= +github.com/zhengxiexie/vsphere-automation-sdk-go/runtime v0.7.3-0.20240808083204-389375dc2535/go.mod h1:DzLetYAmw1+vj7bqElRWEpuy40WYE/woL3alsymYa/c= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt v0.12.3-0.20240808083204-389375dc2535 h1:VIVbs8Vg/V5ntux2RFOAUw7p0p1BQVKulcoejvq0U54= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt v0.12.3-0.20240808083204-389375dc2535/go.mod h1:ODLiES6L4kslLAgLcLHPJJo7j1ez08hyJDIH0RTDGl0= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt-mp v0.6.3-0.20240808083204-389375dc2535 h1:MywC6dY0e3FAauytiZkTZ5myAhgTy0piytXBpGr+VGU= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt-mp v0.6.3-0.20240808083204-389375dc2535/go.mod h1:qcPRwB7KlQRpGFZs0HDzqOxXljIl2Szh7SPRvKUj0Ww= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -253,17 +181,17 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -271,11 +199,11 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -284,16 +212,13 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -302,66 +227,44 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= -k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= -k8s.io/apiextensions-apiserver v0.29.3 h1:9HF+EtZaVpFjStakF4yVufnXGPRppWFEQ87qnO91YeI= -k8s.io/apiextensions-apiserver v0.29.3/go.mod h1:po0XiY5scnpJfFizNGo6puNU6Fq6D70UJY2Cb2KwAVc= -k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= -k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= -k8s.io/apiserver v0.29.3 h1:xR7ELlJ/BZSr2n4CnD3lfA4gzFivh0wwfNfz9L0WZcE= -k8s.io/apiserver v0.29.3/go.mod h1:hrvXlwfRulbMbBgmWRQlFru2b/JySDpmzvQwwk4GUOs= -k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= -k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= -k8s.io/code-generator v0.29.3 h1:m7E25/t9R9NvejspO2zBdyu+/Gl0Z5m7dCRc680KS14= -k8s.io/code-generator v0.29.3/go.mod h1:x47ofBhN4gxYFcxeKA1PYXeaPreAGaDN85Y/lNUsPoM= -k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= -k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= -k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks= -k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kms v0.29.3 h1:ReljsAUhYlm2spdT4yXmY+9a8x8dc/OT4mXvwQPPteQ= -k8s.io/kms v0.29.3/go.mod h1:TBGbJKpRUMk59neTMDMddjIDL+D4HuFUbpuiuzmOPg0= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= +k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/code-generator v0.30.1 h1:ZsG++q5Vt0ScmKCeLhynUuWgcwFGg1Hl1AGfatqPJBI= +k8s.io/code-generator v0.30.1/go.mod h1:hFgxRsvOUg79mbpbVKfjJvRhVz1qLoe40yZDJ/hwRH4= +k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo= +k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= -sigs.k8s.io/controller-runtime v0.16.0 h1:5koYaaRVBHDr0LZAJjO5dWzUjMsh6cwa7q1Mmusrdvk= -sigs.k8s.io/controller-runtime v0.16.0/go.mod h1:77DnuwA8+J7AO0njzv3wbNlMOnGuLrwFr8JPNwx3J7g= +sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= +sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index a39156ae3..fea0bf948 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,2 +1,2 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 3ad782247..7522374b4 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -5,25 +5,18 @@ set -o nounset set -o pipefail set -o xtrace -APIS=./pkg/apis APIS_PKG=github.com/vmware-tanzu/nsx-operator/pkg/apis OUTPUT_PKG=github.com/vmware-tanzu/nsx-operator/pkg/client -GROUP=nsx.vmware.com +GROUP=vpc SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. CODEGEN_PKG=$(go env GOMODCACHE)/k8s.io/code-generator@v0.27.1 -rm -fr "${APIS:?}/${GROUP:?}" rm -fr ./pkg/client -for VERSION in v1alpha1 v1alpha2; do - mkdir -p "${APIS}/${GROUP}/${VERSION}" - cp -r "${APIS}/${VERSION}"/* "${APIS}/${GROUP}/${VERSION}/" -done - bash "${CODEGEN_PKG}"/generate-groups.sh "deepcopy,client,informer,lister" \ ${OUTPUT_PKG} ${APIS_PKG} \ -${GROUP}:v1alpha1,v1alpha2 \ +${GROUP}:v1alpha1 \ --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt \ --output-base "${SCRIPT_ROOT}" -v 10 diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/condition_types.go b/pkg/apis/legacy/v1alpha1/condition_types.go similarity index 100% rename from pkg/apis/nsx.vmware.com/v1alpha1/condition_types.go rename to pkg/apis/legacy/v1alpha1/condition_types.go diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/doc.go b/pkg/apis/legacy/v1alpha1/doc.go similarity index 100% rename from pkg/apis/nsx.vmware.com/v1alpha1/doc.go rename to pkg/apis/legacy/v1alpha1/doc.go diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/groupversion_info.go b/pkg/apis/legacy/v1alpha1/groupversion_info.go similarity index 100% rename from pkg/apis/nsx.vmware.com/v1alpha1/groupversion_info.go rename to pkg/apis/legacy/v1alpha1/groupversion_info.go diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/nsxserviceaccount_types.go b/pkg/apis/legacy/v1alpha1/nsxserviceaccount_types.go similarity index 100% rename from pkg/apis/nsx.vmware.com/v1alpha1/nsxserviceaccount_types.go rename to pkg/apis/legacy/v1alpha1/nsxserviceaccount_types.go diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/register.go b/pkg/apis/legacy/v1alpha1/register.go similarity index 100% rename from pkg/apis/nsx.vmware.com/v1alpha1/register.go rename to pkg/apis/legacy/v1alpha1/register.go diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/securitypolicy_types.go b/pkg/apis/legacy/v1alpha1/securitypolicy_types.go similarity index 100% rename from pkg/apis/nsx.vmware.com/v1alpha1/securitypolicy_types.go rename to pkg/apis/legacy/v1alpha1/securitypolicy_types.go diff --git a/pkg/apis/legacy/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/legacy/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..e3bcbb8bb --- /dev/null +++ b/pkg/apis/legacy/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,458 @@ +//go:build !ignore_autogenerated + +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Condition) DeepCopyInto(out *Condition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. +func (in *Condition) DeepCopy() *Condition { + if in == nil { + return nil + } + out := new(Condition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPBlock) DeepCopyInto(out *IPBlock) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlock. +func (in *IPBlock) DeepCopy() *IPBlock { + if in == nil { + return nil + } + out := new(IPBlock) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXProxyEndpoint) DeepCopyInto(out *NSXProxyEndpoint) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]NSXProxyEndpointAddress, len(*in)) + copy(*out, *in) + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]NSXProxyEndpointPort, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpoint. +func (in *NSXProxyEndpoint) DeepCopy() *NSXProxyEndpoint { + if in == nil { + return nil + } + out := new(NSXProxyEndpoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXProxyEndpointAddress) DeepCopyInto(out *NSXProxyEndpointAddress) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointAddress. +func (in *NSXProxyEndpointAddress) DeepCopy() *NSXProxyEndpointAddress { + if in == nil { + return nil + } + out := new(NSXProxyEndpointAddress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXProxyEndpointPort) DeepCopyInto(out *NSXProxyEndpointPort) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointPort. +func (in *NSXProxyEndpointPort) DeepCopy() *NSXProxyEndpointPort { + if in == nil { + return nil + } + out := new(NSXProxyEndpointPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXSecret) DeepCopyInto(out *NSXSecret) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXSecret. +func (in *NSXSecret) DeepCopy() *NSXSecret { + if in == nil { + return nil + } + out := new(NSXSecret) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccount) DeepCopyInto(out *NSXServiceAccount) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccount. +func (in *NSXServiceAccount) DeepCopy() *NSXServiceAccount { + if in == nil { + return nil + } + out := new(NSXServiceAccount) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NSXServiceAccount) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccountList) DeepCopyInto(out *NSXServiceAccountList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NSXServiceAccount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountList. +func (in *NSXServiceAccountList) DeepCopy() *NSXServiceAccountList { + if in == nil { + return nil + } + out := new(NSXServiceAccountList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NSXServiceAccountList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccountSpec) DeepCopyInto(out *NSXServiceAccountSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountSpec. +func (in *NSXServiceAccountSpec) DeepCopy() *NSXServiceAccountSpec { + if in == nil { + return nil + } + out := new(NSXServiceAccountSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccountStatus) DeepCopyInto(out *NSXServiceAccountStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NSXManagers != nil { + in, out := &in.NSXManagers, &out.NSXManagers + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.ProxyEndpoints.DeepCopyInto(&out.ProxyEndpoints) + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make([]NSXSecret, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountStatus. +func (in *NSXServiceAccountStatus) DeepCopy() *NSXServiceAccountStatus { + if in == nil { + return nil + } + out := new(NSXServiceAccountStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicy) DeepCopyInto(out *SecurityPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicy. +func (in *SecurityPolicy) DeepCopy() *SecurityPolicy { + if in == nil { + return nil + } + out := new(SecurityPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SecurityPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyList) DeepCopyInto(out *SecurityPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SecurityPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyList. +func (in *SecurityPolicyList) DeepCopy() *SecurityPolicyList { + if in == nil { + return nil + } + out := new(SecurityPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SecurityPolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyPeer) DeepCopyInto(out *SecurityPolicyPeer) { + *out = *in + if in.VMSelector != nil { + in, out := &in.VMSelector, &out.VMSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.PodSelector != nil { + in, out := &in.PodSelector, &out.PodSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.IPBlocks != nil { + in, out := &in.IPBlocks, &out.IPBlocks + *out = make([]IPBlock, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyPeer. +func (in *SecurityPolicyPeer) DeepCopy() *SecurityPolicyPeer { + if in == nil { + return nil + } + out := new(SecurityPolicyPeer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyPort) DeepCopyInto(out *SecurityPolicyPort) { + *out = *in + out.Port = in.Port +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyPort. +func (in *SecurityPolicyPort) DeepCopy() *SecurityPolicyPort { + if in == nil { + return nil + } + out := new(SecurityPolicyPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyRule) DeepCopyInto(out *SecurityPolicyRule) { + *out = *in + if in.Action != nil { + in, out := &in.Action, &out.Action + *out = new(RuleAction) + **out = **in + } + if in.AppliedTo != nil { + in, out := &in.AppliedTo, &out.AppliedTo + *out = make([]SecurityPolicyTarget, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Direction != nil { + in, out := &in.Direction, &out.Direction + *out = new(RuleDirection) + **out = **in + } + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]SecurityPolicyPeer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Destinations != nil { + in, out := &in.Destinations, &out.Destinations + *out = make([]SecurityPolicyPeer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]SecurityPolicyPort, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyRule. +func (in *SecurityPolicyRule) DeepCopy() *SecurityPolicyRule { + if in == nil { + return nil + } + out := new(SecurityPolicyRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicySpec) DeepCopyInto(out *SecurityPolicySpec) { + *out = *in + if in.AppliedTo != nil { + in, out := &in.AppliedTo, &out.AppliedTo + *out = make([]SecurityPolicyTarget, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]SecurityPolicyRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicySpec. +func (in *SecurityPolicySpec) DeepCopy() *SecurityPolicySpec { + if in == nil { + return nil + } + out := new(SecurityPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyStatus) DeepCopyInto(out *SecurityPolicyStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyStatus. +func (in *SecurityPolicyStatus) DeepCopy() *SecurityPolicyStatus { + if in == nil { + return nil + } + out := new(SecurityPolicyStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyTarget) DeepCopyInto(out *SecurityPolicyTarget) { + *out = *in + if in.VMSelector != nil { + in, out := &in.VMSelector, &out.VMSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.PodSelector != nil { + in, out := &in.PodSelector, &out.PodSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyTarget. +func (in *SecurityPolicyTarget) DeepCopy() *SecurityPolicyTarget { + if in == nil { + return nil + } + out := new(SecurityPolicyTarget) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/ippool_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/ippool_types.go deleted file mode 100644 index 6620529b0..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha1/ippool_types.go +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// IPPool is the Schema for the ippools API. -type IPPool struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata"` - - Spec IPPoolSpec `json:"spec"` - Status IPPoolStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// IPPoolList contains a list of IPPool. -type IPPoolList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []IPPool `json:"items"` -} - -// IPPoolSpec defines the desired state of IPPool. -type IPPoolSpec struct { - // Subnets defines set of subnets need to be allocated. - // +optional - Subnets []SubnetRequest `json:"subnets"` -} - -// IPPoolStatus defines the observed state of IPPool. -type IPPoolStatus struct { - // Subnets defines subnets allocation result. - Subnets []SubnetResult `json:"subnets"` - // Conditions defines current state of the IPPool. - Conditions []Condition `json:"conditions"` -} - -// SubnetRequest defines the subnet allocation request. -type SubnetRequest struct { - // PrefixLength defines prefix length for this subnet. - PrefixLength int `json:"prefixLength,omitempty"` - - // IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. - // This is optional, the default is IPv4. - // +kubebuilder:validation:Enum=IPv4;IPv6 - // +kubebuilder:default=IPv4 - IPFamily string `json:"ipFamily,omitempty"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -// SubnetResult defines the subnet allocation result. -type SubnetResult struct { - // CIDR defines the allocated CIDR. - CIDR string `json:"cidr"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -func init() { - SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/networkinfo_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/networkinfo_types.go deleted file mode 100644 index 5d09cb221..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha1/networkinfo_types.go +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright © 2024 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:storageversion - -// NetworkInfo is used to report the network information for a namespace. -type NetworkInfo struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - VPCs []VPCState `json:"vpcs"` -} - -//+kubebuilder:object:root=true - -// NetworkInfoList contains a list of NetworkInfo. -type NetworkInfoList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []NetworkInfo `json:"items"` -} - -// VPCState defines information for VPC. -type VPCState struct { - // VPC name. - Name string `json:"name"` - // NSX Policy path for VPC. - VPCPath string `json:"vpcPath"` - // Default SNAT IP for Private Subnets. - DefaultSNATIP string `json:"defaultSNATIP"` - // LoadBalancerIPAddresses (AVI SE Subnet CIDR or NSX LB SNAT IPs). - LoadBalancerIPAddresses string `json:"loadBalancerIPAddresses,omitempty"` - // Private CIDRs used for the VPC. - PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs,omitempty"` -} - -func init() { - SchemeBuilder.Register(&NetworkInfo{}, &NetworkInfoList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/staticroute_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/staticroute_types.go deleted file mode 100644 index 87d6b7b80..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha1/staticroute_types.go +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type StaticRouteStatusCondition string - -// StaticRouteCondition defines condition of StaticRoute. -type StaticRouteCondition Condition - -// StaticRouteSpec defines static routes configuration on VPC. -type StaticRouteSpec struct { - // Specify network address in CIDR format. - // +kubebuilder:validation:Format=cidr - Network string `json:"network"` - // Next hop gateway - // +kubebuilder:validation:MinItems=1 - NextHops []NextHop `json:"nextHops"` -} - -// NextHop defines next hop configuration for network. -type NextHop struct { - // Next hop gateway IP address. - // +kubebuilder:validation:Format=ip - IPAddress string `json:"ipAddress"` -} - -// StaticRouteStatus defines the observed state of StaticRoute. -type StaticRouteStatus struct { - Conditions []StaticRouteCondition `json:"conditions"` - NSXResourcePath string `json:"nsxResourcePath"` -} - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// StaticRoute is the Schema for the staticroutes API. -// +kubebuilder:printcolumn:name="Network",type=string,JSONPath=`.spec.network`,description="Network in CIDR format" -// +kubebuilder:printcolumn:name="NextHops",type=string,JSONPath=`.spec.nextHops[*].ipAddress`,description="Next Hops" -type StaticRoute struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec StaticRouteSpec `json:"spec,omitempty"` - Status StaticRouteStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// StaticRouteList contains a list of StaticRoute. -type StaticRouteList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []StaticRoute `json:"items"` -} - -func init() { - SchemeBuilder.Register(&StaticRoute{}, &StaticRouteList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go deleted file mode 100644 index 5473a8021..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type AccessMode string - -// SubnetSpec defines the desired state of Subnet. -type SubnetSpec struct { - // Size of Subnet based upon estimated workload count. - // +kubebuilder:validation:Maximum:=65536 - // +kubebuilder:validation:Minimum:=16 - IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` - // Access mode of Subnet, accessible only from within VPC or from outside VPC. - // +kubebuilder:validation:Enum=Private;Public - AccessMode AccessMode `json:"accessMode,omitempty"` - // Subnet CIDRS. - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=2 - IPAddresses []string `json:"ipAddresses,omitempty"` - // Subnet advanced configuration. - AdvancedConfig AdvancedConfig `json:"advancedConfig,omitempty"` - // DHCPConfig DHCP configuration. - DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` -} - -// SubnetStatus defines the observed state of Subnet. -type SubnetStatus struct { - NSXResourcePath string `json:"nsxResourcePath,omitempty"` - IPAddresses []string `json:"ipAddresses,omitempty"` - Conditions []Condition `json:"conditions,omitempty"` -} - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// Subnet is the Schema for the subnets API. -// +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" -// +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" -// +kubebuilder:printcolumn:name="IPAddresses",type=string,JSONPath=`.status.ipAddresses[*]`,description="CIDRs for the Subnet" -type Subnet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec SubnetSpec `json:"spec,omitempty"` - Status SubnetStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// SubnetList contains a list of Subnet. -type SubnetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Subnet `json:"items"` -} - -// AdvancedConfig is Subnet advanced configuration. -type AdvancedConfig struct { - // StaticIPAllocation configuration for subnet ports with VIF attachment. - StaticIPAllocation StaticIPAllocation `json:"staticIPAllocation,omitempty"` -} - -// StaticIPAllocation is static IP allocation for subnet ports with VIF attachment. -type StaticIPAllocation struct { - // Enable or disable static IP allocation for subnet ports with VIF attachment. - // +kubebuilder:default:=false - Enable bool `json:"enable,omitempty"` -} - -// DHCPConfig is DHCP configuration. -type DHCPConfig struct { - // +kubebuilder:default:=false - EnableDHCP bool `json:"enableDHCP,omitempty"` - // DHCPRelayConfigPath is policy path of DHCP-relay-config. - DHCPRelayConfigPath string `json:"dhcpRelayConfigPath,omitempty"` - // DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - // By default, 80% of IPv4 IPs will be reserved for DHCP. - // Configure 0 if no pool is required. - // +kubebuilder:default:=80 - // +kubebuilder:validation:Maximum:=100 - // +kubebuilder:validation:Minimum:=0 - DHCPV4PoolSize int `json:"dhcpV4PoolSize,omitempty"` - // DHCPV6PoolSize number of IPs to be reserved for DHCP ranges. - // By default, 2000 IPv6 IPs will be reserved for DHCP. - // +kubebuilder:default:=2000 - DHCPV6PoolSize int `json:"dhcpV6PoolSize,omitempty"` - DNSClientConfig DNSClientConfig `json:"dnsClientConfig,omitempty"` -} - -// DNSClientConfig holds DNS configurations. -type DNSClientConfig struct { - DNSServersIPs []string `json:"dnsServersIPs,omitempty"` -} - -func init() { - SchemeBuilder.Register(&Subnet{}, &SubnetList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/vpc_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/vpc_types.go deleted file mode 100644 index 2a5282bf9..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha1/vpc_types.go +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// VPC is the Schema for the VPC API -// +kubebuilder:printcolumn:name="PrivateIPv4CIDRs",type=string,JSONPath=`.status.privateIPv4CIDRs`,description="Private IPv4 CIDRs" -// +kubebuilder:printcolumn:name="SNATIP",type=string,JSONPath=`.status.defaultSNATIP`,description="Default SNAT IP for Private Subnets" -// +kubebuilder:printcolumn:name="LBSubnetCIDR",type=string,JSONPath=`.status.lbSubnetCIDR`,description="CIDR for the load balancer Subnet" -type VPC struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec VPCSpec `json:"spec,omitempty"` - Status VPCStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// VPCList contains a list of VPC -type VPCList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []VPC `json:"items"` -} - -// VPCSpec defines VPC configuration -type VPCSpec struct { -} - -// VPCStatus defines the observed state of VPC -type VPCStatus struct { - Conditions []Condition `json:"conditions"` - // NSX VPC Policy API resource path. - NSXResourcePath string `json:"nsxResourcePath"` - // Default SNAT IP for Private Subnets. - DefaultSNATIP string `json:"defaultSNATIP"` - // NSX PolicyPath for the load balancer Subnet. - LBSubnetPath string `json:"lbSubnetPath"` - // CIDR for the load balancer Subnet. - LBSubnetCIDR string `json:"lbSubnetCIDR"` - // Private CIDRs used for the VPC. - PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs"` -} - -func init() { - SchemeBuilder.Register(&VPC{}, &VPCList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go deleted file mode 100644 index 9ba4babbc..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// +kubebuilder:object:generate=true -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - AccessModePublic string = "Public" - AccessModePrivate string = "Private" -) - -// VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. -// There is a default VPCNetworkConfiguration that applies to Namespaces -// do not have a VPCNetworkConfiguration assigned. When a field is not set -// in a Namespace's VPCNetworkConfiguration, the Namespace will use the value -// in the default VPCNetworkConfiguration. -type VPCNetworkConfigurationSpec struct { - // PolicyPath of Tier0 or Tier0 VRF gateway. - DefaultGatewayPath string `json:"defaultGatewayPath,omitempty"` - // Edge cluster path on which the networking elements will be created. - EdgeClusterPath string `json:"edgeClusterPath,omitempty"` - // NSX-T Project the Namespace associated with. - NSXTProject string `json:"nsxtProject,omitempty"` - // NSX-T IPv4 Block paths used to allocate external Subnets. - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=5 - ExternalIPv4Blocks []string `json:"externalIPv4Blocks,omitempty"` - // Private IPv4 CIDRs used to allocate Private Subnets. - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=5 - PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs,omitempty"` - // Default size of Subnet based upon estimated workload count. - // Defaults to 26. - // +kubebuilder:default=26 - DefaultIPv4SubnetSize int `json:"defaultIPv4SubnetSize,omitempty"` - // DefaultSubnetAccessMode defines the access mode of the default SubnetSet for PodVM and VM. - // Must be Public or Private. - // +kubebuilder:validation:Enum=Public;Private - DefaultSubnetAccessMode string `json:"defaultSubnetAccessMode,omitempty"` - // ShortID specifies Identifier to use when displaying VPC context in logs. - // Less than or equal to 8 characters. - // +kubebuilder:validation:MaxLength=8 - // +optional - ShortID string `json:"shortID,omitempty"` -} - -// VPCNetworkConfigurationStatus defines the observed state of VPCNetworkConfiguration -type VPCNetworkConfigurationStatus struct { - // VPCs describes VPC info, now it includes lb Subnet info which are needed for AKO. - VPCs []VPCInfo `json:"vpcs,omitempty"` -} - -// VPCInfo defines VPC info needed by tenant admin. -type VPCInfo struct { - // VPC name. - Name string `json:"name"` - // AVISESubnetPath is the NSX Policy Path for the AVI SE Subnet. - AVISESubnetPath string `json:"lbSubnetPath,omitempty"` -} - -// +genclient -// +genclient:nonNamespaced -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations API. -// +kubebuilder:resource:scope="Cluster" -// +kubebuilder:printcolumn:name="NSXTProject",type=string,JSONPath=`.spec.nsxtProject`,description="NSXTProject the Namespace associated with" -// +kubebuilder:printcolumn:name="ExternalIPv4Blocks",type=string,JSONPath=`.spec.externalIPv4Blocks`,description="ExternalIPv4Blocks assigned to the Namespace" -// +kubebuilder:printcolumn:name="PrivateIPv4CIDRs",type=string,JSONPath=`.spec.privateIPv4CIDRs`,description="PrivateIPv4CIDRs assigned to the Namespace" -type VPCNetworkConfiguration struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec VPCNetworkConfigurationSpec `json:"spec,omitempty"` - Status VPCNetworkConfigurationStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// VPCNetworkConfigurationList contains a list of VPCNetworkConfiguration. -type VPCNetworkConfigurationList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []VPCNetworkConfiguration `json:"items"` -} - -func init() { - SchemeBuilder.Register(&VPCNetworkConfiguration{}, &VPCNetworkConfigurationList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha2/doc.go b/pkg/apis/nsx.vmware.com/v1alpha2/doc.go deleted file mode 100644 index 440321155..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha2/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// +k8s:deepcopy-gen=package -// +groupName=nsx.vmware.com - -package v1alpha2 diff --git a/pkg/apis/nsx.vmware.com/v1alpha2/groupversion_info.go b/pkg/apis/nsx.vmware.com/v1alpha2/groupversion_info.go deleted file mode 100644 index 17358a516..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha2/groupversion_info.go +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Package v1alpha2 contains API Schema definitions for the v1alpha2 API group -// +kubebuilder:object:generate=true -// +groupName=nsx.vmware.com -package v1alpha2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "nsx.vmware.com", Version: "v1alpha2"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/pkg/apis/nsx.vmware.com/v1alpha2/ippool_types.go b/pkg/apis/nsx.vmware.com/v1alpha2/ippool_types.go deleted file mode 100644 index 469dc43ef..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha2/ippool_types.go +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha2 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// IPPool is the Schema for the ippools API. -// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type`,description="Type of IPPool" -// +kubebuilder:printcolumn:name="Subnets",type=string,JSONPath=`.status.subnets[*].cidr`,description="CIDRs for the Subnet" -type IPPool struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata"` - - Spec IPPoolSpec `json:"spec"` - Status IPPoolStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// IPPoolList contains a list of IPPool. -type IPPoolList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []IPPool `json:"items"` -} - -// IPPoolSpec defines the desired state of IPPool. -type IPPoolSpec struct { - // Type defines the type of this IPPool, Public or Private. - // +kubebuilder:validation:Enum=Public;Private - // +optional - Type string `json:"type,omitempty"` - // Subnets defines set of subnets need to be allocated. - // +optional - Subnets []SubnetRequest `json:"subnets"` -} - -// IPPoolStatus defines the observed state of IPPool. -type IPPoolStatus struct { - // Subnets defines subnets allocation result. - Subnets []SubnetResult `json:"subnets"` - // Conditions defines current state of the IPPool. - Conditions []v1alpha1.Condition `json:"conditions"` -} - -// SubnetRequest defines the subnet allocation request. -type SubnetRequest struct { - // PrefixLength defines prefix length for this subnet. - PrefixLength int `json:"prefixLength,omitempty"` - - // IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. - // This is optional, the default is IPv4. - // +kubebuilder:validation:Enum=IPv4;IPv6 - // +kubebuilder:default=IPv4 - IPFamily string `json:"ipFamily,omitempty"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -// SubnetResult defines the subnet allocation result. -type SubnetResult struct { - // CIDR defines the allocated CIDR. - CIDR string `json:"cidr"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -func init() { - SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha2/register.go b/pkg/apis/nsx.vmware.com/v1alpha2/register.go deleted file mode 100644 index 26d0e5656..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha2/register.go +++ /dev/null @@ -1,12 +0,0 @@ -package v1alpha2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// SchemeGroupVersion is group version used to register these objects. -var SchemeGroupVersion = GroupVersion - -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} diff --git a/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go deleted file mode 100644 index 7dadeb757..000000000 --- a/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go +++ /dev/null @@ -1,150 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPool) DeepCopyInto(out *IPPool) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. -func (in *IPPool) DeepCopy() *IPPool { - if in == nil { - return nil - } - out := new(IPPool) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPool) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]IPPool, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. -func (in *IPPoolList) DeepCopy() *IPPoolList { - if in == nil { - return nil - } - out := new(IPPoolList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPoolList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { - *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetRequest, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. -func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { - if in == nil { - return nil - } - out := new(IPPoolSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { - *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetResult, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1alpha1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. -func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { - if in == nil { - return nil - } - out := new(IPPoolStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetRequest) DeepCopyInto(out *SubnetRequest) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetRequest. -func (in *SubnetRequest) DeepCopy() *SubnetRequest { - if in == nil { - return nil - } - out := new(SubnetRequest) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetResult) DeepCopyInto(out *SubnetResult) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResult. -func (in *SubnetResult) DeepCopy() *SubnetResult { - if in == nil { - return nil - } - out := new(SubnetResult) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/apis/v1alpha1/ippool_types.go b/pkg/apis/v1alpha1/ippool_types.go deleted file mode 100644 index 6620529b0..000000000 --- a/pkg/apis/v1alpha1/ippool_types.go +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// IPPool is the Schema for the ippools API. -type IPPool struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata"` - - Spec IPPoolSpec `json:"spec"` - Status IPPoolStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// IPPoolList contains a list of IPPool. -type IPPoolList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []IPPool `json:"items"` -} - -// IPPoolSpec defines the desired state of IPPool. -type IPPoolSpec struct { - // Subnets defines set of subnets need to be allocated. - // +optional - Subnets []SubnetRequest `json:"subnets"` -} - -// IPPoolStatus defines the observed state of IPPool. -type IPPoolStatus struct { - // Subnets defines subnets allocation result. - Subnets []SubnetResult `json:"subnets"` - // Conditions defines current state of the IPPool. - Conditions []Condition `json:"conditions"` -} - -// SubnetRequest defines the subnet allocation request. -type SubnetRequest struct { - // PrefixLength defines prefix length for this subnet. - PrefixLength int `json:"prefixLength,omitempty"` - - // IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. - // This is optional, the default is IPv4. - // +kubebuilder:validation:Enum=IPv4;IPv6 - // +kubebuilder:default=IPv4 - IPFamily string `json:"ipFamily,omitempty"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -// SubnetResult defines the subnet allocation result. -type SubnetResult struct { - // CIDR defines the allocated CIDR. - CIDR string `json:"cidr"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -func init() { - SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) -} diff --git a/pkg/apis/v1alpha1/nsxserviceaccount_types.go b/pkg/apis/v1alpha1/nsxserviceaccount_types.go deleted file mode 100644 index d086bb33e..000000000 --- a/pkg/apis/v1alpha1/nsxserviceaccount_types.go +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright © 2022 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// NSXServiceAccountSpec defines the desired state of NSXServiceAccount -type NSXServiceAccountSpec struct { - VPCName string `json:"vpcName,omitempty"` - // EnableCertRotation enables cert rotation feature in this cluster when NSXT >=4.1.3 - EnableCertRotation bool `json:"enableCertRotation,omitempty"` -} - -type NSXProxyEndpointAddress struct { - Hostname string `json:"hostname,omitempty"` - //+kubebuilder:validation:Format=ip - IP string `json:"ip,omitempty"` -} - -type NSXProxyProtocol string - -const ( - NSXProxyProtocolTCP NSXProxyProtocol = "TCP" -) - -type NSXProxyEndpointPort struct { - Name string `json:"name,omitempty"` - Port uint16 `json:"port,omitempty"` - Protocol NSXProxyProtocol `json:"protocol,omitempty"` -} - -type NSXProxyEndpoint struct { - Addresses []NSXProxyEndpointAddress `json:"addresses,omitempty"` - Ports []NSXProxyEndpointPort `json:"ports,omitempty"` -} - -type NSXSecret struct { - Name string `json:"name"` - Namespace string `json:"namespace"` -} - -type NSXServiceAccountPhase string - -const ( - NSXServiceAccountPhaseRealized NSXServiceAccountPhase = "realized" - NSXServiceAccountPhaseInProgress NSXServiceAccountPhase = "inProgress" - NSXServiceAccountPhaseFailed NSXServiceAccountPhase = "failed" - - ConditionTypeRealized string = "Realized" - ConditionReasonRealizationSuccess string = "RealizationSuccess" - ConditionReasonRealizationError string = "RealizationError" -) - -// NSXServiceAccountStatus defines the observed state of NSXServiceAccount -type NSXServiceAccountStatus struct { - Phase NSXServiceAccountPhase `json:"phase,omitempty"` - Reason string `json:"reason,omitempty"` - // Represents the realization status of a NSXServiceAccount's current state. - // Known .status.conditions.type is: "Realized" - Conditions []metav1.Condition `json:"conditions,omitempty"` - VPCPath string `json:"vpcPath,omitempty"` - NSXManagers []string `json:"nsxManagers,omitempty"` - ProxyEndpoints NSXProxyEndpoint `json:"proxyEndpoints,omitempty"` - ClusterID string `json:"clusterID,omitempty"` - ClusterName string `json:"clusterName,omitempty"` - Secrets []NSXSecret `json:"secrets,omitempty"` -} - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// NSXServiceAccount is the Schema for the nsxserviceaccounts API -type NSXServiceAccount struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec NSXServiceAccountSpec `json:"spec,omitempty"` - Status NSXServiceAccountStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// NSXServiceAccountList contains a list of NSXServiceAccount -type NSXServiceAccountList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []NSXServiceAccount `json:"items"` -} - -func init() { - SchemeBuilder.Register(&NSXServiceAccount{}, &NSXServiceAccountList{}) -} diff --git a/pkg/apis/v1alpha1/subnet_types.go b/pkg/apis/v1alpha1/subnet_types.go deleted file mode 100644 index 5473a8021..000000000 --- a/pkg/apis/v1alpha1/subnet_types.go +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type AccessMode string - -// SubnetSpec defines the desired state of Subnet. -type SubnetSpec struct { - // Size of Subnet based upon estimated workload count. - // +kubebuilder:validation:Maximum:=65536 - // +kubebuilder:validation:Minimum:=16 - IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` - // Access mode of Subnet, accessible only from within VPC or from outside VPC. - // +kubebuilder:validation:Enum=Private;Public - AccessMode AccessMode `json:"accessMode,omitempty"` - // Subnet CIDRS. - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=2 - IPAddresses []string `json:"ipAddresses,omitempty"` - // Subnet advanced configuration. - AdvancedConfig AdvancedConfig `json:"advancedConfig,omitempty"` - // DHCPConfig DHCP configuration. - DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` -} - -// SubnetStatus defines the observed state of Subnet. -type SubnetStatus struct { - NSXResourcePath string `json:"nsxResourcePath,omitempty"` - IPAddresses []string `json:"ipAddresses,omitempty"` - Conditions []Condition `json:"conditions,omitempty"` -} - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// Subnet is the Schema for the subnets API. -// +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" -// +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" -// +kubebuilder:printcolumn:name="IPAddresses",type=string,JSONPath=`.status.ipAddresses[*]`,description="CIDRs for the Subnet" -type Subnet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec SubnetSpec `json:"spec,omitempty"` - Status SubnetStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// SubnetList contains a list of Subnet. -type SubnetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Subnet `json:"items"` -} - -// AdvancedConfig is Subnet advanced configuration. -type AdvancedConfig struct { - // StaticIPAllocation configuration for subnet ports with VIF attachment. - StaticIPAllocation StaticIPAllocation `json:"staticIPAllocation,omitempty"` -} - -// StaticIPAllocation is static IP allocation for subnet ports with VIF attachment. -type StaticIPAllocation struct { - // Enable or disable static IP allocation for subnet ports with VIF attachment. - // +kubebuilder:default:=false - Enable bool `json:"enable,omitempty"` -} - -// DHCPConfig is DHCP configuration. -type DHCPConfig struct { - // +kubebuilder:default:=false - EnableDHCP bool `json:"enableDHCP,omitempty"` - // DHCPRelayConfigPath is policy path of DHCP-relay-config. - DHCPRelayConfigPath string `json:"dhcpRelayConfigPath,omitempty"` - // DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - // By default, 80% of IPv4 IPs will be reserved for DHCP. - // Configure 0 if no pool is required. - // +kubebuilder:default:=80 - // +kubebuilder:validation:Maximum:=100 - // +kubebuilder:validation:Minimum:=0 - DHCPV4PoolSize int `json:"dhcpV4PoolSize,omitempty"` - // DHCPV6PoolSize number of IPs to be reserved for DHCP ranges. - // By default, 2000 IPv6 IPs will be reserved for DHCP. - // +kubebuilder:default:=2000 - DHCPV6PoolSize int `json:"dhcpV6PoolSize,omitempty"` - DNSClientConfig DNSClientConfig `json:"dnsClientConfig,omitempty"` -} - -// DNSClientConfig holds DNS configurations. -type DNSClientConfig struct { - DNSServersIPs []string `json:"dnsServersIPs,omitempty"` -} - -func init() { - SchemeBuilder.Register(&Subnet{}, &SubnetList{}) -} diff --git a/pkg/apis/v1alpha1/subnetport_types.go b/pkg/apis/v1alpha1/subnetport_types.go deleted file mode 100644 index 8c128a6e7..000000000 --- a/pkg/apis/v1alpha1/subnetport_types.go +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// SubnetPortSpec defines the desired state of SubnetPort. -type SubnetPortSpec struct { - // Subnet defines the parent Subnet name of the SubnetPort. - Subnet string `json:"subnet,omitempty"` - // SubnetSet defines the parent SubnetSet name of the SubnetPort. - SubnetSet string `json:"subnetSet,omitempty"` -} - -// SubnetPortStatus defines the observed state of SubnetPort. -type SubnetPortStatus struct { - // Conditions describes current state of SubnetPort. - Conditions []Condition `json:"conditions,omitempty"` - // Subnet port attachment state. - Attachment SegmentPortAttachmentState `json:"attachment,omitempty"` - NetworkInterfaceConfig NetworkInterfaceConfig `json:"networkInterfaceConfig,omitempty"` -} - -// VIF attachment state of a subnet port. -type SegmentPortAttachmentState struct { - ID string `json:"id,omitempty"` -} - -type NetworkInterfaceConfig struct { - LogicalSwitchUUID string `json:"logicalSwitchUUID,omitempty"` - IPAddresses []NetworkInterfaceIPAddress `json:"ipAddresses,omitempty"` - MACAddress string `json:"macAddress,omitempty"` -} - -type NetworkInterfaceIPAddress struct { - // IP address string with the prefix. - IPAddress string `json:"ipAddress,omitempty"` - Gateway string `json:"gateway,omitempty"` -} - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// SubnetPort is the Schema for the subnetports API. -// +kubebuilder:printcolumn:name="VIFID",type=string,JSONPath=`.status.attachment.id`,description="Attachment VIF ID owned by the SubnetPort." -// +kubebuilder:printcolumn:name="IPAddress",type=string,JSONPath=`.status.networkInterfaceConfig.ipAddresses[0].ipAddress`,description="IP address string with the prefix." -// +kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.status.networkInterfaceConfig.macAddress`,description="MAC Address of the SubnetPort." -type SubnetPort struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec SubnetPortSpec `json:"spec,omitempty"` - Status SubnetPortStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// SubnetPortList contains a list of SubnetPort. -type SubnetPortList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []SubnetPort `json:"items"` -} - -func init() { - SchemeBuilder.Register(&SubnetPort{}, &SubnetPortList{}) -} diff --git a/pkg/apis/v1alpha1/subnetset_types.go b/pkg/apis/v1alpha1/subnetset_types.go deleted file mode 100644 index 5c6864893..000000000 --- a/pkg/apis/v1alpha1/subnetset_types.go +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// SubnetSetSpec defines the desired state of SubnetSet. -type SubnetSetSpec struct { - // Size of Subnet based upon estimated workload count. - // +kubebuilder:validation:Maximum:=65536 - // +kubebuilder:validation:Minimum:=16 - IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` - // Access mode of Subnet, accessible only from within VPC or from outside VPC. - // +kubebuilder:validation:Enum=Private;Public - AccessMode AccessMode `json:"accessMode,omitempty"` - // Subnet advanced configuration. - AdvancedConfig AdvancedConfig `json:"advancedConfig,omitempty"` - // DHCPConfig DHCP configuration. - DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` -} - -// SubnetInfo defines the observed state of a single Subnet of a SubnetSet. -type SubnetInfo struct { - NSXResourcePath string `json:"nsxResourcePath"` - IPAddresses []string `json:"ipAddresses"` -} - -// SubnetSetStatus defines the observed state of SubnetSet. -type SubnetSetStatus struct { - Conditions []Condition `json:"conditions,omitempty"` - Subnets []SubnetInfo `json:"subnets,omitempty"` -} - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// SubnetSet is the Schema for the subnetsets API. -// +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" -// +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" -// +kubebuilder:printcolumn:name="IPAddresses",type=string,JSONPath=`.status.subnets[*].ipAddresses[*]`,description="CIDRs for the Subnet" -type SubnetSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec SubnetSetSpec `json:"spec,omitempty"` - Status SubnetSetStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// SubnetSetList contains a list of SubnetSet. -type SubnetSetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []SubnetSet `json:"items"` -} - -func init() { - SchemeBuilder.Register(&SubnetSet{}, &SubnetSetList{}) -} diff --git a/pkg/apis/v1alpha1/vpc_types.go b/pkg/apis/v1alpha1/vpc_types.go deleted file mode 100644 index 2a5282bf9..000000000 --- a/pkg/apis/v1alpha1/vpc_types.go +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// VPC is the Schema for the VPC API -// +kubebuilder:printcolumn:name="PrivateIPv4CIDRs",type=string,JSONPath=`.status.privateIPv4CIDRs`,description="Private IPv4 CIDRs" -// +kubebuilder:printcolumn:name="SNATIP",type=string,JSONPath=`.status.defaultSNATIP`,description="Default SNAT IP for Private Subnets" -// +kubebuilder:printcolumn:name="LBSubnetCIDR",type=string,JSONPath=`.status.lbSubnetCIDR`,description="CIDR for the load balancer Subnet" -type VPC struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec VPCSpec `json:"spec,omitempty"` - Status VPCStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// VPCList contains a list of VPC -type VPCList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []VPC `json:"items"` -} - -// VPCSpec defines VPC configuration -type VPCSpec struct { -} - -// VPCStatus defines the observed state of VPC -type VPCStatus struct { - Conditions []Condition `json:"conditions"` - // NSX VPC Policy API resource path. - NSXResourcePath string `json:"nsxResourcePath"` - // Default SNAT IP for Private Subnets. - DefaultSNATIP string `json:"defaultSNATIP"` - // NSX PolicyPath for the load balancer Subnet. - LBSubnetPath string `json:"lbSubnetPath"` - // CIDR for the load balancer Subnet. - LBSubnetCIDR string `json:"lbSubnetCIDR"` - // Private CIDRs used for the VPC. - PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs"` -} - -func init() { - SchemeBuilder.Register(&VPC{}, &VPCList{}) -} diff --git a/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go deleted file mode 100644 index 9ba4babbc..000000000 --- a/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// +kubebuilder:object:generate=true -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - AccessModePublic string = "Public" - AccessModePrivate string = "Private" -) - -// VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. -// There is a default VPCNetworkConfiguration that applies to Namespaces -// do not have a VPCNetworkConfiguration assigned. When a field is not set -// in a Namespace's VPCNetworkConfiguration, the Namespace will use the value -// in the default VPCNetworkConfiguration. -type VPCNetworkConfigurationSpec struct { - // PolicyPath of Tier0 or Tier0 VRF gateway. - DefaultGatewayPath string `json:"defaultGatewayPath,omitempty"` - // Edge cluster path on which the networking elements will be created. - EdgeClusterPath string `json:"edgeClusterPath,omitempty"` - // NSX-T Project the Namespace associated with. - NSXTProject string `json:"nsxtProject,omitempty"` - // NSX-T IPv4 Block paths used to allocate external Subnets. - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=5 - ExternalIPv4Blocks []string `json:"externalIPv4Blocks,omitempty"` - // Private IPv4 CIDRs used to allocate Private Subnets. - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=5 - PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs,omitempty"` - // Default size of Subnet based upon estimated workload count. - // Defaults to 26. - // +kubebuilder:default=26 - DefaultIPv4SubnetSize int `json:"defaultIPv4SubnetSize,omitempty"` - // DefaultSubnetAccessMode defines the access mode of the default SubnetSet for PodVM and VM. - // Must be Public or Private. - // +kubebuilder:validation:Enum=Public;Private - DefaultSubnetAccessMode string `json:"defaultSubnetAccessMode,omitempty"` - // ShortID specifies Identifier to use when displaying VPC context in logs. - // Less than or equal to 8 characters. - // +kubebuilder:validation:MaxLength=8 - // +optional - ShortID string `json:"shortID,omitempty"` -} - -// VPCNetworkConfigurationStatus defines the observed state of VPCNetworkConfiguration -type VPCNetworkConfigurationStatus struct { - // VPCs describes VPC info, now it includes lb Subnet info which are needed for AKO. - VPCs []VPCInfo `json:"vpcs,omitempty"` -} - -// VPCInfo defines VPC info needed by tenant admin. -type VPCInfo struct { - // VPC name. - Name string `json:"name"` - // AVISESubnetPath is the NSX Policy Path for the AVI SE Subnet. - AVISESubnetPath string `json:"lbSubnetPath,omitempty"` -} - -// +genclient -// +genclient:nonNamespaced -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations API. -// +kubebuilder:resource:scope="Cluster" -// +kubebuilder:printcolumn:name="NSXTProject",type=string,JSONPath=`.spec.nsxtProject`,description="NSXTProject the Namespace associated with" -// +kubebuilder:printcolumn:name="ExternalIPv4Blocks",type=string,JSONPath=`.spec.externalIPv4Blocks`,description="ExternalIPv4Blocks assigned to the Namespace" -// +kubebuilder:printcolumn:name="PrivateIPv4CIDRs",type=string,JSONPath=`.spec.privateIPv4CIDRs`,description="PrivateIPv4CIDRs assigned to the Namespace" -type VPCNetworkConfiguration struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec VPCNetworkConfigurationSpec `json:"spec,omitempty"` - Status VPCNetworkConfigurationStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// VPCNetworkConfigurationList contains a list of VPCNetworkConfiguration. -type VPCNetworkConfigurationList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []VPCNetworkConfiguration `json:"items"` -} - -func init() { - SchemeBuilder.Register(&VPCNetworkConfiguration{}, &VPCNetworkConfigurationList{}) -} diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index ae17587b7..000000000 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,1479 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AdvancedConfig) DeepCopyInto(out *AdvancedConfig) { - *out = *in - out.StaticIPAllocation = in.StaticIPAllocation -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdvancedConfig. -func (in *AdvancedConfig) DeepCopy() *AdvancedConfig { - if in == nil { - return nil - } - out := new(AdvancedConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { - if in == nil { - return nil - } - out := new(Condition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DHCPConfig) DeepCopyInto(out *DHCPConfig) { - *out = *in - in.DNSClientConfig.DeepCopyInto(&out.DNSClientConfig) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPConfig. -func (in *DHCPConfig) DeepCopy() *DHCPConfig { - if in == nil { - return nil - } - out := new(DHCPConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSClientConfig) DeepCopyInto(out *DNSClientConfig) { - *out = *in - if in.DNSServersIPs != nil { - in, out := &in.DNSServersIPs, &out.DNSServersIPs - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSClientConfig. -func (in *DNSClientConfig) DeepCopy() *DNSClientConfig { - if in == nil { - return nil - } - out := new(DNSClientConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPBlock) DeepCopyInto(out *IPBlock) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlock. -func (in *IPBlock) DeepCopy() *IPBlock { - if in == nil { - return nil - } - out := new(IPBlock) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPool) DeepCopyInto(out *IPPool) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. -func (in *IPPool) DeepCopy() *IPPool { - if in == nil { - return nil - } - out := new(IPPool) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPool) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]IPPool, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. -func (in *IPPoolList) DeepCopy() *IPPoolList { - if in == nil { - return nil - } - out := new(IPPoolList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPoolList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { - *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetRequest, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. -func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { - if in == nil { - return nil - } - out := new(IPPoolSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { - *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetResult, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. -func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { - if in == nil { - return nil - } - out := new(IPPoolStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpoint) DeepCopyInto(out *NSXProxyEndpoint) { - *out = *in - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]NSXProxyEndpointAddress, len(*in)) - copy(*out, *in) - } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = make([]NSXProxyEndpointPort, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpoint. -func (in *NSXProxyEndpoint) DeepCopy() *NSXProxyEndpoint { - if in == nil { - return nil - } - out := new(NSXProxyEndpoint) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpointAddress) DeepCopyInto(out *NSXProxyEndpointAddress) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointAddress. -func (in *NSXProxyEndpointAddress) DeepCopy() *NSXProxyEndpointAddress { - if in == nil { - return nil - } - out := new(NSXProxyEndpointAddress) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpointPort) DeepCopyInto(out *NSXProxyEndpointPort) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointPort. -func (in *NSXProxyEndpointPort) DeepCopy() *NSXProxyEndpointPort { - if in == nil { - return nil - } - out := new(NSXProxyEndpointPort) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXSecret) DeepCopyInto(out *NSXSecret) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXSecret. -func (in *NSXSecret) DeepCopy() *NSXSecret { - if in == nil { - return nil - } - out := new(NSXSecret) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccount) DeepCopyInto(out *NSXServiceAccount) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccount. -func (in *NSXServiceAccount) DeepCopy() *NSXServiceAccount { - if in == nil { - return nil - } - out := new(NSXServiceAccount) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NSXServiceAccount) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountList) DeepCopyInto(out *NSXServiceAccountList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]NSXServiceAccount, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountList. -func (in *NSXServiceAccountList) DeepCopy() *NSXServiceAccountList { - if in == nil { - return nil - } - out := new(NSXServiceAccountList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NSXServiceAccountList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountSpec) DeepCopyInto(out *NSXServiceAccountSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountSpec. -func (in *NSXServiceAccountSpec) DeepCopy() *NSXServiceAccountSpec { - if in == nil { - return nil - } - out := new(NSXServiceAccountSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountStatus) DeepCopyInto(out *NSXServiceAccountStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.NSXManagers != nil { - in, out := &in.NSXManagers, &out.NSXManagers - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.ProxyEndpoints.DeepCopyInto(&out.ProxyEndpoints) - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]NSXSecret, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountStatus. -func (in *NSXServiceAccountStatus) DeepCopy() *NSXServiceAccountStatus { - if in == nil { - return nil - } - out := new(NSXServiceAccountStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkInfo) DeepCopyInto(out *NetworkInfo) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.VPCs != nil { - in, out := &in.VPCs, &out.VPCs - *out = make([]VPCState, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInfo. -func (in *NetworkInfo) DeepCopy() *NetworkInfo { - if in == nil { - return nil - } - out := new(NetworkInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkInfo) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkInfoList) DeepCopyInto(out *NetworkInfoList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]NetworkInfo, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInfoList. -func (in *NetworkInfoList) DeepCopy() *NetworkInfoList { - if in == nil { - return nil - } - out := new(NetworkInfoList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkInfoList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkInterfaceConfig) DeepCopyInto(out *NetworkInterfaceConfig) { - *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses - *out = make([]NetworkInterfaceIPAddress, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInterfaceConfig. -func (in *NetworkInterfaceConfig) DeepCopy() *NetworkInterfaceConfig { - if in == nil { - return nil - } - out := new(NetworkInterfaceConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkInterfaceIPAddress) DeepCopyInto(out *NetworkInterfaceIPAddress) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInterfaceIPAddress. -func (in *NetworkInterfaceIPAddress) DeepCopy() *NetworkInterfaceIPAddress { - if in == nil { - return nil - } - out := new(NetworkInterfaceIPAddress) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NextHop) DeepCopyInto(out *NextHop) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NextHop. -func (in *NextHop) DeepCopy() *NextHop { - if in == nil { - return nil - } - out := new(NextHop) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicy) DeepCopyInto(out *SecurityPolicy) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicy. -func (in *SecurityPolicy) DeepCopy() *SecurityPolicy { - if in == nil { - return nil - } - out := new(SecurityPolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SecurityPolicy) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicyList) DeepCopyInto(out *SecurityPolicyList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]SecurityPolicy, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyList. -func (in *SecurityPolicyList) DeepCopy() *SecurityPolicyList { - if in == nil { - return nil - } - out := new(SecurityPolicyList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SecurityPolicyList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicyPeer) DeepCopyInto(out *SecurityPolicyPeer) { - *out = *in - if in.VMSelector != nil { - in, out := &in.VMSelector, &out.VMSelector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.PodSelector != nil { - in, out := &in.PodSelector, &out.PodSelector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.NamespaceSelector != nil { - in, out := &in.NamespaceSelector, &out.NamespaceSelector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.IPBlocks != nil { - in, out := &in.IPBlocks, &out.IPBlocks - *out = make([]IPBlock, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyPeer. -func (in *SecurityPolicyPeer) DeepCopy() *SecurityPolicyPeer { - if in == nil { - return nil - } - out := new(SecurityPolicyPeer) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicyPort) DeepCopyInto(out *SecurityPolicyPort) { - *out = *in - out.Port = in.Port -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyPort. -func (in *SecurityPolicyPort) DeepCopy() *SecurityPolicyPort { - if in == nil { - return nil - } - out := new(SecurityPolicyPort) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicyRule) DeepCopyInto(out *SecurityPolicyRule) { - *out = *in - if in.Action != nil { - in, out := &in.Action, &out.Action - *out = new(RuleAction) - **out = **in - } - if in.AppliedTo != nil { - in, out := &in.AppliedTo, &out.AppliedTo - *out = make([]SecurityPolicyTarget, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Direction != nil { - in, out := &in.Direction, &out.Direction - *out = new(RuleDirection) - **out = **in - } - if in.Sources != nil { - in, out := &in.Sources, &out.Sources - *out = make([]SecurityPolicyPeer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Destinations != nil { - in, out := &in.Destinations, &out.Destinations - *out = make([]SecurityPolicyPeer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = make([]SecurityPolicyPort, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyRule. -func (in *SecurityPolicyRule) DeepCopy() *SecurityPolicyRule { - if in == nil { - return nil - } - out := new(SecurityPolicyRule) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicySpec) DeepCopyInto(out *SecurityPolicySpec) { - *out = *in - if in.AppliedTo != nil { - in, out := &in.AppliedTo, &out.AppliedTo - *out = make([]SecurityPolicyTarget, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Rules != nil { - in, out := &in.Rules, &out.Rules - *out = make([]SecurityPolicyRule, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicySpec. -func (in *SecurityPolicySpec) DeepCopy() *SecurityPolicySpec { - if in == nil { - return nil - } - out := new(SecurityPolicySpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicyStatus) DeepCopyInto(out *SecurityPolicyStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyStatus. -func (in *SecurityPolicyStatus) DeepCopy() *SecurityPolicyStatus { - if in == nil { - return nil - } - out := new(SecurityPolicyStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityPolicyTarget) DeepCopyInto(out *SecurityPolicyTarget) { - *out = *in - if in.VMSelector != nil { - in, out := &in.VMSelector, &out.VMSelector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.PodSelector != nil { - in, out := &in.PodSelector, &out.PodSelector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyTarget. -func (in *SecurityPolicyTarget) DeepCopy() *SecurityPolicyTarget { - if in == nil { - return nil - } - out := new(SecurityPolicyTarget) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SegmentPortAttachmentState) DeepCopyInto(out *SegmentPortAttachmentState) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SegmentPortAttachmentState. -func (in *SegmentPortAttachmentState) DeepCopy() *SegmentPortAttachmentState { - if in == nil { - return nil - } - out := new(SegmentPortAttachmentState) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticIPAllocation) DeepCopyInto(out *StaticIPAllocation) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticIPAllocation. -func (in *StaticIPAllocation) DeepCopy() *StaticIPAllocation { - if in == nil { - return nil - } - out := new(StaticIPAllocation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticRoute) DeepCopyInto(out *StaticRoute) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRoute. -func (in *StaticRoute) DeepCopy() *StaticRoute { - if in == nil { - return nil - } - out := new(StaticRoute) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *StaticRoute) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticRouteCondition) DeepCopyInto(out *StaticRouteCondition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteCondition. -func (in *StaticRouteCondition) DeepCopy() *StaticRouteCondition { - if in == nil { - return nil - } - out := new(StaticRouteCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticRouteList) DeepCopyInto(out *StaticRouteList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]StaticRoute, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteList. -func (in *StaticRouteList) DeepCopy() *StaticRouteList { - if in == nil { - return nil - } - out := new(StaticRouteList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *StaticRouteList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticRouteSpec) DeepCopyInto(out *StaticRouteSpec) { - *out = *in - if in.NextHops != nil { - in, out := &in.NextHops, &out.NextHops - *out = make([]NextHop, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteSpec. -func (in *StaticRouteSpec) DeepCopy() *StaticRouteSpec { - if in == nil { - return nil - } - out := new(StaticRouteSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticRouteStatus) DeepCopyInto(out *StaticRouteStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]StaticRouteCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteStatus. -func (in *StaticRouteStatus) DeepCopy() *StaticRouteStatus { - if in == nil { - return nil - } - out := new(StaticRouteStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Subnet) DeepCopyInto(out *Subnet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subnet. -func (in *Subnet) DeepCopy() *Subnet { - if in == nil { - return nil - } - out := new(Subnet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Subnet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetInfo) DeepCopyInto(out *SubnetInfo) { - *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetInfo. -func (in *SubnetInfo) DeepCopy() *SubnetInfo { - if in == nil { - return nil - } - out := new(SubnetInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetList) DeepCopyInto(out *SubnetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Subnet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetList. -func (in *SubnetList) DeepCopy() *SubnetList { - if in == nil { - return nil - } - out := new(SubnetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SubnetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetPort) DeepCopyInto(out *SubnetPort) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPort. -func (in *SubnetPort) DeepCopy() *SubnetPort { - if in == nil { - return nil - } - out := new(SubnetPort) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SubnetPort) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetPortList) DeepCopyInto(out *SubnetPortList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]SubnetPort, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPortList. -func (in *SubnetPortList) DeepCopy() *SubnetPortList { - if in == nil { - return nil - } - out := new(SubnetPortList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SubnetPortList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetPortSpec) DeepCopyInto(out *SubnetPortSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPortSpec. -func (in *SubnetPortSpec) DeepCopy() *SubnetPortSpec { - if in == nil { - return nil - } - out := new(SubnetPortSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetPortStatus) DeepCopyInto(out *SubnetPortStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - out.Attachment = in.Attachment - in.NetworkInterfaceConfig.DeepCopyInto(&out.NetworkInterfaceConfig) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPortStatus. -func (in *SubnetPortStatus) DeepCopy() *SubnetPortStatus { - if in == nil { - return nil - } - out := new(SubnetPortStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetRequest) DeepCopyInto(out *SubnetRequest) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetRequest. -func (in *SubnetRequest) DeepCopy() *SubnetRequest { - if in == nil { - return nil - } - out := new(SubnetRequest) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetResult) DeepCopyInto(out *SubnetResult) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResult. -func (in *SubnetResult) DeepCopy() *SubnetResult { - if in == nil { - return nil - } - out := new(SubnetResult) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetSet) DeepCopyInto(out *SubnetSet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSet. -func (in *SubnetSet) DeepCopy() *SubnetSet { - if in == nil { - return nil - } - out := new(SubnetSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SubnetSet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetSetList) DeepCopyInto(out *SubnetSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]SubnetSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetList. -func (in *SubnetSetList) DeepCopy() *SubnetSetList { - if in == nil { - return nil - } - out := new(SubnetSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SubnetSetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetSetSpec) DeepCopyInto(out *SubnetSetSpec) { - *out = *in - out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetSpec. -func (in *SubnetSetSpec) DeepCopy() *SubnetSetSpec { - if in == nil { - return nil - } - out := new(SubnetSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetSetStatus) DeepCopyInto(out *SubnetSetStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetInfo, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetStatus. -func (in *SubnetSetStatus) DeepCopy() *SubnetSetStatus { - if in == nil { - return nil - } - out := new(SubnetSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { - *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses - *out = make([]string, len(*in)) - copy(*out, *in) - } - out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. -func (in *SubnetSpec) DeepCopy() *SubnetSpec { - if in == nil { - return nil - } - out := new(SubnetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { - *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetStatus. -func (in *SubnetStatus) DeepCopy() *SubnetStatus { - if in == nil { - return nil - } - out := new(SubnetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPC) DeepCopyInto(out *VPC) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPC. -func (in *VPC) DeepCopy() *VPC { - if in == nil { - return nil - } - out := new(VPC) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VPC) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCInfo) DeepCopyInto(out *VPCInfo) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCInfo. -func (in *VPCInfo) DeepCopy() *VPCInfo { - if in == nil { - return nil - } - out := new(VPCInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCList) DeepCopyInto(out *VPCList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]VPC, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCList. -func (in *VPCList) DeepCopy() *VPCList { - if in == nil { - return nil - } - out := new(VPCList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VPCList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCNetworkConfiguration) DeepCopyInto(out *VPCNetworkConfiguration) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfiguration. -func (in *VPCNetworkConfiguration) DeepCopy() *VPCNetworkConfiguration { - if in == nil { - return nil - } - out := new(VPCNetworkConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VPCNetworkConfiguration) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCNetworkConfigurationList) DeepCopyInto(out *VPCNetworkConfigurationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]VPCNetworkConfiguration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationList. -func (in *VPCNetworkConfigurationList) DeepCopy() *VPCNetworkConfigurationList { - if in == nil { - return nil - } - out := new(VPCNetworkConfigurationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VPCNetworkConfigurationList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCNetworkConfigurationSpec) DeepCopyInto(out *VPCNetworkConfigurationSpec) { - *out = *in - if in.ExternalIPv4Blocks != nil { - in, out := &in.ExternalIPv4Blocks, &out.ExternalIPv4Blocks - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.PrivateIPv4CIDRs != nil { - in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationSpec. -func (in *VPCNetworkConfigurationSpec) DeepCopy() *VPCNetworkConfigurationSpec { - if in == nil { - return nil - } - out := new(VPCNetworkConfigurationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCNetworkConfigurationStatus) DeepCopyInto(out *VPCNetworkConfigurationStatus) { - *out = *in - if in.VPCs != nil { - in, out := &in.VPCs, &out.VPCs - *out = make([]VPCInfo, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationStatus. -func (in *VPCNetworkConfigurationStatus) DeepCopy() *VPCNetworkConfigurationStatus { - if in == nil { - return nil - } - out := new(VPCNetworkConfigurationStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCSpec) DeepCopyInto(out *VPCSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCSpec. -func (in *VPCSpec) DeepCopy() *VPCSpec { - if in == nil { - return nil - } - out := new(VPCSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCState) DeepCopyInto(out *VPCState) { - *out = *in - if in.PrivateIPv4CIDRs != nil { - in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCState. -func (in *VPCState) DeepCopy() *VPCState { - if in == nil { - return nil - } - out := new(VPCState) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCStatus) DeepCopyInto(out *VPCStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.PrivateIPv4CIDRs != nil { - in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCStatus. -func (in *VPCStatus) DeepCopy() *VPCStatus { - if in == nil { - return nil - } - out := new(VPCStatus) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/apis/v1alpha2/doc.go b/pkg/apis/v1alpha2/doc.go deleted file mode 100644 index 440321155..000000000 --- a/pkg/apis/v1alpha2/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// +k8s:deepcopy-gen=package -// +groupName=nsx.vmware.com - -package v1alpha2 diff --git a/pkg/apis/v1alpha2/groupversion_info.go b/pkg/apis/v1alpha2/groupversion_info.go deleted file mode 100644 index 17358a516..000000000 --- a/pkg/apis/v1alpha2/groupversion_info.go +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Package v1alpha2 contains API Schema definitions for the v1alpha2 API group -// +kubebuilder:object:generate=true -// +groupName=nsx.vmware.com -package v1alpha2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "nsx.vmware.com", Version: "v1alpha2"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/pkg/apis/v1alpha2/ippool_types.go b/pkg/apis/v1alpha2/ippool_types.go deleted file mode 100644 index 469dc43ef..000000000 --- a/pkg/apis/v1alpha2/ippool_types.go +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package v1alpha2 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" -) - -// +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion - -// IPPool is the Schema for the ippools API. -// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type`,description="Type of IPPool" -// +kubebuilder:printcolumn:name="Subnets",type=string,JSONPath=`.status.subnets[*].cidr`,description="CIDRs for the Subnet" -type IPPool struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata"` - - Spec IPPoolSpec `json:"spec"` - Status IPPoolStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// IPPoolList contains a list of IPPool. -type IPPoolList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []IPPool `json:"items"` -} - -// IPPoolSpec defines the desired state of IPPool. -type IPPoolSpec struct { - // Type defines the type of this IPPool, Public or Private. - // +kubebuilder:validation:Enum=Public;Private - // +optional - Type string `json:"type,omitempty"` - // Subnets defines set of subnets need to be allocated. - // +optional - Subnets []SubnetRequest `json:"subnets"` -} - -// IPPoolStatus defines the observed state of IPPool. -type IPPoolStatus struct { - // Subnets defines subnets allocation result. - Subnets []SubnetResult `json:"subnets"` - // Conditions defines current state of the IPPool. - Conditions []v1alpha1.Condition `json:"conditions"` -} - -// SubnetRequest defines the subnet allocation request. -type SubnetRequest struct { - // PrefixLength defines prefix length for this subnet. - PrefixLength int `json:"prefixLength,omitempty"` - - // IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. - // This is optional, the default is IPv4. - // +kubebuilder:validation:Enum=IPv4;IPv6 - // +kubebuilder:default=IPv4 - IPFamily string `json:"ipFamily,omitempty"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -// SubnetResult defines the subnet allocation result. -type SubnetResult struct { - // CIDR defines the allocated CIDR. - CIDR string `json:"cidr"` - - // Name defines the name of this subnet. - Name string `json:"name"` -} - -func init() { - SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) -} diff --git a/pkg/apis/v1alpha2/register.go b/pkg/apis/v1alpha2/register.go deleted file mode 100644 index 26d0e5656..000000000 --- a/pkg/apis/v1alpha2/register.go +++ /dev/null @@ -1,12 +0,0 @@ -package v1alpha2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// SchemeGroupVersion is group version used to register these objects. -var SchemeGroupVersion = GroupVersion - -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} diff --git a/pkg/apis/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/v1alpha2/zz_generated.deepcopy.go deleted file mode 100644 index 7dadeb757..000000000 --- a/pkg/apis/v1alpha2/zz_generated.deepcopy.go +++ /dev/null @@ -1,150 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPool) DeepCopyInto(out *IPPool) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. -func (in *IPPool) DeepCopy() *IPPool { - if in == nil { - return nil - } - out := new(IPPool) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPool) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]IPPool, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. -func (in *IPPoolList) DeepCopy() *IPPoolList { - if in == nil { - return nil - } - out := new(IPPoolList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPoolList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { - *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetRequest, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. -func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { - if in == nil { - return nil - } - out := new(IPPoolSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { - *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetResult, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1alpha1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. -func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { - if in == nil { - return nil - } - out := new(IPPoolStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetRequest) DeepCopyInto(out *SubnetRequest) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetRequest. -func (in *SubnetRequest) DeepCopy() *SubnetRequest { - if in == nil { - return nil - } - out := new(SubnetRequest) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetResult) DeepCopyInto(out *SubnetResult) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResult. -func (in *SubnetResult) DeepCopy() *SubnetResult { - if in == nil { - return nil - } - out := new(SubnetResult) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/apis/vpc/v1alpha1/addressbinding_types.go b/pkg/apis/vpc/v1alpha1/addressbinding_types.go new file mode 100644 index 000000000..7d7230128 --- /dev/null +++ b/pkg/apis/vpc/v1alpha1/addressbinding_types.go @@ -0,0 +1,41 @@ +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +type AddressBindingSpec struct { + // VMName contains the VM's name + VMName string `json:"vmName"` + // InterfaceName contains the interface name of the VM, if not set, the first interface of the VM will be used + InterfaceName string `json:"interfaceName,omitempty"` +} + +type AddressBindingStatus struct { + IPAddress string `json:"ipAddress"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// AddressBinding is used to manage 1:1 NAT for a VM/NetworkInterface. +type AddressBinding struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AddressBindingSpec `json:"spec"` + Status AddressBindingStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// AddressBindingList contains a list of AddressBinding. +type AddressBindingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AddressBinding `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AddressBinding{}, &AddressBindingList{}) +} diff --git a/pkg/apis/v1alpha1/condition_types.go b/pkg/apis/vpc/v1alpha1/condition_types.go similarity index 77% rename from pkg/apis/v1alpha1/condition_types.go rename to pkg/apis/vpc/v1alpha1/condition_types.go index 5d708b849..a7d31d45a 100644 --- a/pkg/apis/v1alpha1/condition_types.go +++ b/pkg/apis/vpc/v1alpha1/condition_types.go @@ -8,7 +8,10 @@ import ( type ConditionType string const ( - Ready ConditionType = "Ready" + Ready ConditionType = "Ready" + GatewayConnectionReady ConditionType = "GatewayConnectionReady" + AutoSnatEnabled ConditionType = "AutoSnatEnabled" + ExternalIPBlocksConfigured ConditionType = "ExternalIPBlocksConfigured" ) // Condition defines condition of custom resource. diff --git a/pkg/apis/v1alpha1/doc.go b/pkg/apis/vpc/v1alpha1/doc.go similarity index 58% rename from pkg/apis/v1alpha1/doc.go rename to pkg/apis/vpc/v1alpha1/doc.go index 73e7087ed..f452fd25d 100644 --- a/pkg/apis/v1alpha1/doc.go +++ b/pkg/apis/vpc/v1alpha1/doc.go @@ -1,4 +1,4 @@ // +k8s:deepcopy-gen=package -// +groupName=nsx.vmware.com +// +groupName=crd.nsx.vmware.com package v1alpha1 diff --git a/pkg/apis/v1alpha1/groupversion_info.go b/pkg/apis/vpc/v1alpha1/groupversion_info.go similarity index 82% rename from pkg/apis/v1alpha1/groupversion_info.go rename to pkg/apis/vpc/v1alpha1/groupversion_info.go index 9a64fd3fb..c4d8528f4 100644 --- a/pkg/apis/v1alpha1/groupversion_info.go +++ b/pkg/apis/vpc/v1alpha1/groupversion_info.go @@ -2,7 +2,7 @@ SPDX-License-Identifier: Apache-2.0 */ // +kubebuilder:object:generate=true -// +groupName=nsx.vmware.com +// +groupName=crd.nsx.vmware.com package v1alpha1 import ( @@ -12,7 +12,7 @@ import ( var ( // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "nsx.vmware.com", Version: "v1alpha1"} + GroupVersion = schema.GroupVersion{Group: "crd.nsx.vmware.com", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/pkg/apis/vpc/v1alpha1/ipaddressallocation_types.go b/pkg/apis/vpc/v1alpha1/ipaddressallocation_types.go new file mode 100644 index 000000000..5e992f281 --- /dev/null +++ b/pkg/apis/vpc/v1alpha1/ipaddressallocation_types.go @@ -0,0 +1,61 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +type IPAddressVisibility string + +var ( + IPAddressVisibilityExternal IPAddressVisibility = "External" + IPAddressVisibilityPrivate IPAddressVisibility = "Private" + IPAddressVisibilityPrivateTGW IPAddressVisibility = "PrivateTGW" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// IPAddressAllocation is the Schema for the IP allocation API. +// +kubebuilder:printcolumn:name="IPAddressBlockVisibility",type=string,JSONPath=`.spec.ipAddressBlockVisibility`,description="IPAddressBlockVisibility of IPAddressAllocation" +// +kubebuilder:printcolumn:name="AllocationIPs",type=string,JSONPath=`.status.allocationIPs`, description="AllocationIPs for the IPAddressAllocation" +type IPAddressAllocation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec IPAddressAllocationSpec `json:"spec"` + Status IPAddressAllocationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPAddressAllocationList contains a list of IPAddressAllocation. +type IPAddressAllocationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPAddressAllocation `json:"items"` +} + +// IPAddressAllocationSpec defines the desired state of IPAddressAllocation. +type IPAddressAllocationSpec struct { + // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External, Private or PrivateTGW. + // +kubebuilder:validation:Enum=External;Private;PrivateTGW + // +kubebuilder:default=Private + // +optional + IPAddressBlockVisibility IPAddressVisibility `json:"ipAddressBlockVisibility,omitempty"` + // AllocationSize specifies the size of allocationIPs to be allocated. + AllocationSize int `json:"allocationSize,omitempty"` +} + +// IPAddressAllocationStatus defines the observed state of IPAddressAllocation. +type IPAddressAllocationStatus struct { + // AllocationIPs is the allocated IP addresses + AllocationIPs string `json:"allocationIPs"` + Conditions []Condition `json:"conditions,omitempty"` +} + +func init() { + SchemeBuilder.Register(&IPAddressAllocation{}, &IPAddressAllocationList{}) +} diff --git a/pkg/apis/vpc/v1alpha1/ipblocksinfo_types.go b/pkg/apis/vpc/v1alpha1/ipblocksinfo_types.go new file mode 100644 index 000000000..4cd8f9c16 --- /dev/null +++ b/pkg/apis/vpc/v1alpha1/ipblocksinfo_types.go @@ -0,0 +1,40 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:resource:scope="Cluster",path=ipblocksinfos + +// IPBlocksInfo is the Schema for the ipblocksinfo API +type IPBlocksInfo struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // ExternalIPCIDRs is a list of CIDR strings. Each CIDR is a contiguous IP address + // spaces represented by network address and prefix length. The visibility of the + // IPBlocks is External. + ExternalIPCIDRs []string `json:"externalIPCIDRs,omitempty"` + // PrivateTGWIPCIDRs is a list of CIDR strings. Each CIDR is a contiguous IP address + // spaces represented by network address and prefix length. The visibility of the + // IPBlocks is PrivateTWG. Only IPBlocks in default project will be included. + PrivateTGWIPCIDRs []string `json:"privateTGWIPCIDRs,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPBlocksInfoList contains a list of IPBlocksInfo +type IPBlocksInfoList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPBlocksInfo `json:"items"` +} + +func init() { + SchemeBuilder.Register(&IPBlocksInfo{}, &IPBlocksInfoList{}) +} diff --git a/pkg/apis/v1alpha1/networkinfo_types.go b/pkg/apis/vpc/v1alpha1/networkinfo_types.go similarity index 82% rename from pkg/apis/v1alpha1/networkinfo_types.go rename to pkg/apis/vpc/v1alpha1/networkinfo_types.go index 5d09cb221..0114b87e4 100644 --- a/pkg/apis/v1alpha1/networkinfo_types.go +++ b/pkg/apis/vpc/v1alpha1/networkinfo_types.go @@ -8,10 +8,11 @@ import ( ) // +genclient -//+kubebuilder:object:root=true -//+kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:storageversion // NetworkInfo is used to report the network information for a namespace. +// +kubebuilder:resource:path=networkinfos type NetworkInfo struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -19,7 +20,7 @@ type NetworkInfo struct { VPCs []VPCState `json:"vpcs"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // NetworkInfoList contains a list of NetworkInfo. type NetworkInfoList struct { @@ -32,14 +33,14 @@ type NetworkInfoList struct { type VPCState struct { // VPC name. Name string `json:"name"` - // NSX Policy path for VPC. - VPCPath string `json:"vpcPath"` // Default SNAT IP for Private Subnets. DefaultSNATIP string `json:"defaultSNATIP"` // LoadBalancerIPAddresses (AVI SE Subnet CIDR or NSX LB SNAT IPs). LoadBalancerIPAddresses string `json:"loadBalancerIPAddresses,omitempty"` // Private CIDRs used for the VPC. - PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs,omitempty"` + PrivateIPs []string `json:"privateIPs,omitempty"` + // NSX Policy path for VPC. + VPCPath string `json:"vpcPath,omitempty"` } func init() { diff --git a/pkg/apis/v1alpha1/register.go b/pkg/apis/vpc/v1alpha1/register.go similarity index 100% rename from pkg/apis/v1alpha1/register.go rename to pkg/apis/vpc/v1alpha1/register.go diff --git a/pkg/apis/v1alpha1/securitypolicy_types.go b/pkg/apis/vpc/v1alpha1/securitypolicy_types.go similarity index 100% rename from pkg/apis/v1alpha1/securitypolicy_types.go rename to pkg/apis/vpc/v1alpha1/securitypolicy_types.go diff --git a/pkg/apis/v1alpha1/staticroute_types.go b/pkg/apis/vpc/v1alpha1/staticroute_types.go similarity index 93% rename from pkg/apis/v1alpha1/staticroute_types.go rename to pkg/apis/vpc/v1alpha1/staticroute_types.go index 87d6b7b80..40b02cbd0 100644 --- a/pkg/apis/v1alpha1/staticroute_types.go +++ b/pkg/apis/vpc/v1alpha1/staticroute_types.go @@ -31,8 +31,7 @@ type NextHop struct { // StaticRouteStatus defines the observed state of StaticRoute. type StaticRouteStatus struct { - Conditions []StaticRouteCondition `json:"conditions"` - NSXResourcePath string `json:"nsxResourcePath"` + Conditions []StaticRouteCondition `json:"conditions"` } // +genclient diff --git a/pkg/apis/vpc/v1alpha1/subnet_types.go b/pkg/apis/vpc/v1alpha1/subnet_types.go new file mode 100644 index 000000000..fcd75d7b4 --- /dev/null +++ b/pkg/apis/vpc/v1alpha1/subnet_types.go @@ -0,0 +1,78 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type AccessMode string + +const ( + AccessModePublic string = "Public" + AccessModePrivate string = "Private" + AccessModeProject string = "PrivateTGW" +) + +// SubnetSpec defines the desired state of Subnet. +type SubnetSpec struct { + // Size of Subnet based upon estimated workload count. + // +kubebuilder:validation:Maximum:=65536 + // +kubebuilder:validation:Minimum:=16 + IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` + // Access mode of Subnet, accessible only from within VPC or from outside VPC. + // +kubebuilder:validation:Enum=Private;Public;PrivateTGW + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable" + AccessMode AccessMode `json:"accessMode,omitempty"` + // Subnet CIDRS. + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=2 + IPAddresses []string `json:"ipAddresses,omitempty"` + // DHCPConfig DHCP configuration. + DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` +} + +// SubnetStatus defines the observed state of Subnet. +type SubnetStatus struct { + NetworkAddresses []string `json:"networkAddresses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` + Conditions []Condition `json:"conditions,omitempty"` +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:storageversion + +// Subnet is the Schema for the subnets API. +// +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" +// +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" +// +kubebuilder:printcolumn:name="NetworkAddresses",type=string,JSONPath=`.status.networkAddresses[*]`,description="CIDRs for the Subnet" +type Subnet struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SubnetSpec `json:"spec,omitempty"` + Status SubnetStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// SubnetList contains a list of Subnet. +type SubnetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Subnet `json:"items"` +} + +// DHCPConfig is DHCP configuration. +type DHCPConfig struct { + // +kubebuilder:default:=false + EnableDHCP bool `json:"enableDHCP,omitempty"` +} + +func init() { + SchemeBuilder.Register(&Subnet{}, &SubnetList{}) +} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnetport_types.go b/pkg/apis/vpc/v1alpha1/subnetport_types.go similarity index 91% rename from pkg/apis/nsx.vmware.com/v1alpha1/subnetport_types.go rename to pkg/apis/vpc/v1alpha1/subnetport_types.go index 8c128a6e7..34b592f9c 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnetport_types.go +++ b/pkg/apis/vpc/v1alpha1/subnetport_types.go @@ -20,12 +20,12 @@ type SubnetPortStatus struct { // Conditions describes current state of SubnetPort. Conditions []Condition `json:"conditions,omitempty"` // Subnet port attachment state. - Attachment SegmentPortAttachmentState `json:"attachment,omitempty"` - NetworkInterfaceConfig NetworkInterfaceConfig `json:"networkInterfaceConfig,omitempty"` + Attachment PortAttachment `json:"attachment,omitempty"` + NetworkInterfaceConfig NetworkInterfaceConfig `json:"networkInterfaceConfig,omitempty"` } // VIF attachment state of a subnet port. -type SegmentPortAttachmentState struct { +type PortAttachment struct { ID string `json:"id,omitempty"` } diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go b/pkg/apis/vpc/v1alpha1/subnetset_types.go similarity index 73% rename from pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go rename to pkg/apis/vpc/v1alpha1/subnetset_types.go index 5c6864893..07d5f4b63 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go +++ b/pkg/apis/vpc/v1alpha1/subnetset_types.go @@ -14,18 +14,18 @@ type SubnetSetSpec struct { // +kubebuilder:validation:Minimum:=16 IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` // Access mode of Subnet, accessible only from within VPC or from outside VPC. - // +kubebuilder:validation:Enum=Private;Public + // +kubebuilder:validation:Enum=Private;Public;PrivateTGW + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable" AccessMode AccessMode `json:"accessMode,omitempty"` - // Subnet advanced configuration. - AdvancedConfig AdvancedConfig `json:"advancedConfig,omitempty"` // DHCPConfig DHCP configuration. DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` } // SubnetInfo defines the observed state of a single Subnet of a SubnetSet. type SubnetInfo struct { - NSXResourcePath string `json:"nsxResourcePath"` - IPAddresses []string `json:"ipAddresses"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` } // SubnetSetStatus defines the observed state of SubnetSet. @@ -35,14 +35,14 @@ type SubnetSetStatus struct { } // +genclient -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:storageversion // SubnetSet is the Schema for the subnetsets API. // +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" // +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" -// +kubebuilder:printcolumn:name="IPAddresses",type=string,JSONPath=`.status.subnets[*].ipAddresses[*]`,description="CIDRs for the Subnet" +// +kubebuilder:printcolumn:name="NetworkAddresses",type=string,JSONPath=`.status.subnets[*].networkAddresses[*]`,description="CIDRs for the SubnetSet" type SubnetSet struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -51,7 +51,7 @@ type SubnetSet struct { Status SubnetSetStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // SubnetSetList contains a list of SubnetSet. type SubnetSetList struct { diff --git a/pkg/apis/vpc/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/vpc/v1alpha1/vpcnetworkconfiguration_types.go new file mode 100644 index 000000000..d3a86b5fb --- /dev/null +++ b/pkg/apis/vpc/v1alpha1/vpcnetworkconfiguration_types.go @@ -0,0 +1,89 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// +kubebuilder:object:generate=true +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. +// There is a default VPCNetworkConfiguration that applies to Namespaces +// do not have a VPCNetworkConfiguration assigned. When a field is not set +// in a Namespace's VPCNetworkConfiguration, the Namespace will use the value +// in the default VPCNetworkConfiguration. +type VPCNetworkConfigurationSpec struct { + // NSX path of the VPC the Namespace associated with. + // If VPC is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + // take effect, other fields are ignored. + // +optional + VPC string `json:"vpc,omitempty"` + + // NSX Project the Namespace associated with. + NSXProject string `json:"nsxProject,omitempty"` + + // VPCConnectivityProfile ID. This profile has configuration related to creating VPC transit gateway attachment. + VPCConnectivityProfile string `json:"vpcConnectivityProfile,omitempty"` + + // Private IPs. + PrivateIPs []string `json:"privateIPs,omitempty"` + + // Default size of Subnets. + // Defaults to 32. + // +kubebuilder:default=32 + // +kubebuilder:validation:Maximum:=65536 + // +kubebuilder:validation:Minimum:=16 + DefaultSubnetSize int `json:"defaultSubnetSize,omitempty"` +} + +// VPCNetworkConfigurationStatus defines the observed state of VPCNetworkConfiguration +type VPCNetworkConfigurationStatus struct { + // VPCs describes VPC info, now it includes lb Subnet info which are needed for AKO. + VPCs []VPCInfo `json:"vpcs,omitempty"` + // Conditions describe current state of VPCNetworkConfiguration. + Conditions []Condition `json:"conditions,omitempty"` +} + +// VPCInfo defines VPC info needed by tenant admin. +type VPCInfo struct { + // VPC name. + Name string `json:"name"` + // AVISESubnetPath is the NSX Policy Path for the AVI SE Subnet. + AVISESubnetPath string `json:"lbSubnetPath,omitempty"` + // NSXLoadBalancerPath is the NSX Policy path for the NSX Load Balancer. + NSXLoadBalancerPath string `json:"nsxLoadBalancerPath,omitempty"` + // NSX Policy path for VPC. + VPCPath string `json:"vpcPath"` +} + +// +genclient +// +genclient:nonNamespaced +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:storageversion + +// VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations API. +// +kubebuilder:resource:scope="Cluster" +// +kubebuilder:printcolumn:name="NSXProject",type=string,JSONPath=`.spec.nsxProject`,description="NSXProject the Namespace associated with" +// +kubebuilder:printcolumn:name="PrivateIPs",type=string,JSONPath=`.spec.privateIPs`,description="PrivateIPs assigned to the Namespace" +type VPCNetworkConfiguration struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VPCNetworkConfigurationSpec `json:"spec,omitempty"` + Status VPCNetworkConfigurationStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// VPCNetworkConfigurationList contains a list of VPCNetworkConfiguration. +type VPCNetworkConfigurationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VPCNetworkConfiguration `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VPCNetworkConfiguration{}, &VPCNetworkConfigurationList{}) +} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/vpc/v1alpha1/zz_generated.deepcopy.go similarity index 78% rename from pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go rename to pkg/apis/vpc/v1alpha1/zz_generated.deepcopy.go index ae17587b7..f55b4c9c6 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/vpc/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,6 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by controller-gen. DO NOT EDIT. @@ -14,109 +13,146 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AdvancedConfig) DeepCopyInto(out *AdvancedConfig) { +func (in *AddressBinding) DeepCopyInto(out *AddressBinding) { *out = *in - out.StaticIPAllocation = in.StaticIPAllocation + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdvancedConfig. -func (in *AdvancedConfig) DeepCopy() *AdvancedConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBinding. +func (in *AddressBinding) DeepCopy() *AddressBinding { if in == nil { return nil } - out := new(AdvancedConfig) + out := new(AddressBinding) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressBinding) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { +func (in *AddressBindingList) DeepCopyInto(out *AddressBindingList) { *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AddressBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingList. +func (in *AddressBindingList) DeepCopy() *AddressBindingList { if in == nil { return nil } - out := new(Condition) + out := new(AddressBindingList) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressBindingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DHCPConfig) DeepCopyInto(out *DHCPConfig) { +func (in *AddressBindingSpec) DeepCopyInto(out *AddressBindingSpec) { *out = *in - in.DNSClientConfig.DeepCopyInto(&out.DNSClientConfig) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPConfig. -func (in *DHCPConfig) DeepCopy() *DHCPConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingSpec. +func (in *AddressBindingSpec) DeepCopy() *AddressBindingSpec { if in == nil { return nil } - out := new(DHCPConfig) + out := new(AddressBindingSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSClientConfig) DeepCopyInto(out *DNSClientConfig) { +func (in *AddressBindingStatus) DeepCopyInto(out *AddressBindingStatus) { *out = *in - if in.DNSServersIPs != nil { - in, out := &in.DNSServersIPs, &out.DNSServersIPs - *out = make([]string, len(*in)) - copy(*out, *in) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingStatus. +func (in *AddressBindingStatus) DeepCopy() *AddressBindingStatus { + if in == nil { + return nil } + out := new(AddressBindingStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Condition) DeepCopyInto(out *Condition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSClientConfig. -func (in *DNSClientConfig) DeepCopy() *DNSClientConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. +func (in *Condition) DeepCopy() *Condition { if in == nil { return nil } - out := new(DNSClientConfig) + out := new(Condition) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPBlock) DeepCopyInto(out *IPBlock) { +func (in *DHCPConfig) DeepCopyInto(out *DHCPConfig) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlock. -func (in *IPBlock) DeepCopy() *IPBlock { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPConfig. +func (in *DHCPConfig) DeepCopy() *DHCPConfig { if in == nil { return nil } - out := new(IPBlock) + out := new(DHCPConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPool) DeepCopyInto(out *IPPool) { +func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. -func (in *IPPool) DeepCopy() *IPPool { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. +func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { if in == nil { return nil } - out := new(IPPool) + out := new(IPAddressAllocation) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPool) DeepCopyObject() runtime.Object { +func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -124,31 +160,31 @@ func (in *IPPool) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { +func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]IPPool, len(*in)) + *out = make([]IPAddressAllocation, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. -func (in *IPPoolList) DeepCopy() *IPPoolList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. +func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { if in == nil { return nil } - out := new(IPPoolList) + out := new(IPAddressAllocationList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPPoolList) DeepCopyObject() runtime.Object { +func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -156,33 +192,23 @@ func (in *IPPoolList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { +func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetRequest, len(*in)) - copy(*out, *in) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. -func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. +func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { if in == nil { return nil } - out := new(IPPoolSpec) + out := new(IPAddressAllocationSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { +func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { *out = *in - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]SubnetResult, len(*in)) - copy(*out, *in) - } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make([]Condition, len(*in)) @@ -192,107 +218,60 @@ func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. -func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { - if in == nil { - return nil - } - out := new(IPPoolStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpoint) DeepCopyInto(out *NSXProxyEndpoint) { - *out = *in - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]NSXProxyEndpointAddress, len(*in)) - copy(*out, *in) - } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = make([]NSXProxyEndpointPort, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpoint. -func (in *NSXProxyEndpoint) DeepCopy() *NSXProxyEndpoint { - if in == nil { - return nil - } - out := new(NSXProxyEndpoint) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpointAddress) DeepCopyInto(out *NSXProxyEndpointAddress) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointAddress. -func (in *NSXProxyEndpointAddress) DeepCopy() *NSXProxyEndpointAddress { - if in == nil { - return nil - } - out := new(NSXProxyEndpointAddress) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpointPort) DeepCopyInto(out *NSXProxyEndpointPort) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointPort. -func (in *NSXProxyEndpointPort) DeepCopy() *NSXProxyEndpointPort { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. +func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { if in == nil { return nil } - out := new(NSXProxyEndpointPort) + out := new(IPAddressAllocationStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXSecret) DeepCopyInto(out *NSXSecret) { +func (in *IPBlock) DeepCopyInto(out *IPBlock) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXSecret. -func (in *NSXSecret) DeepCopy() *NSXSecret { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlock. +func (in *IPBlock) DeepCopy() *IPBlock { if in == nil { return nil } - out := new(NSXSecret) + out := new(IPBlock) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccount) DeepCopyInto(out *NSXServiceAccount) { +func (in *IPBlocksInfo) DeepCopyInto(out *IPBlocksInfo) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) + if in.ExternalIPCIDRs != nil { + in, out := &in.ExternalIPCIDRs, &out.ExternalIPCIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PrivateTGWIPCIDRs != nil { + in, out := &in.PrivateTGWIPCIDRs, &out.PrivateTGWIPCIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccount. -func (in *NSXServiceAccount) DeepCopy() *NSXServiceAccount { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlocksInfo. +func (in *IPBlocksInfo) DeepCopy() *IPBlocksInfo { if in == nil { return nil } - out := new(NSXServiceAccount) + out := new(IPBlocksInfo) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NSXServiceAccount) DeepCopyObject() runtime.Object { +func (in *IPBlocksInfo) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -300,85 +279,37 @@ func (in *NSXServiceAccount) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountList) DeepCopyInto(out *NSXServiceAccountList) { +func (in *IPBlocksInfoList) DeepCopyInto(out *IPBlocksInfoList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]NSXServiceAccount, len(*in)) + *out = make([]IPBlocksInfo, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountList. -func (in *NSXServiceAccountList) DeepCopy() *NSXServiceAccountList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlocksInfoList. +func (in *IPBlocksInfoList) DeepCopy() *IPBlocksInfoList { if in == nil { return nil } - out := new(NSXServiceAccountList) + out := new(IPBlocksInfoList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NSXServiceAccountList) DeepCopyObject() runtime.Object { +func (in *IPBlocksInfoList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountSpec) DeepCopyInto(out *NSXServiceAccountSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountSpec. -func (in *NSXServiceAccountSpec) DeepCopy() *NSXServiceAccountSpec { - if in == nil { - return nil - } - out := new(NSXServiceAccountSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountStatus) DeepCopyInto(out *NSXServiceAccountStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.NSXManagers != nil { - in, out := &in.NSXManagers, &out.NSXManagers - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.ProxyEndpoints.DeepCopyInto(&out.ProxyEndpoints) - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]NSXSecret, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountStatus. -func (in *NSXServiceAccountStatus) DeepCopy() *NSXServiceAccountStatus { - if in == nil { - return nil - } - out := new(NSXServiceAccountStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkInfo) DeepCopyInto(out *NetworkInfo) { *out = *in @@ -493,6 +424,21 @@ func (in *NextHop) DeepCopy() *NextHop { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortAttachment) DeepCopyInto(out *PortAttachment) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortAttachment. +func (in *PortAttachment) DeepCopy() *PortAttachment { + if in == nil { + return nil + } + out := new(PortAttachment) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SecurityPolicy) DeepCopyInto(out *SecurityPolicy) { *out = *in @@ -730,36 +676,6 @@ func (in *SecurityPolicyTarget) DeepCopy() *SecurityPolicyTarget { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SegmentPortAttachmentState) DeepCopyInto(out *SegmentPortAttachmentState) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SegmentPortAttachmentState. -func (in *SegmentPortAttachmentState) DeepCopy() *SegmentPortAttachmentState { - if in == nil { - return nil - } - out := new(SegmentPortAttachmentState) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StaticIPAllocation) DeepCopyInto(out *StaticIPAllocation) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticIPAllocation. -func (in *StaticIPAllocation) DeepCopy() *StaticIPAllocation { - if in == nil { - return nil - } - out := new(StaticIPAllocation) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StaticRoute) DeepCopyInto(out *StaticRoute) { *out = *in @@ -907,8 +823,18 @@ func (in *Subnet) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetInfo) DeepCopyInto(out *SubnetInfo) { *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses *out = make([]string, len(*in)) copy(*out, *in) } @@ -1054,42 +980,12 @@ func (in *SubnetPortStatus) DeepCopy() *SubnetPortStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetRequest) DeepCopyInto(out *SubnetRequest) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetRequest. -func (in *SubnetRequest) DeepCopy() *SubnetRequest { - if in == nil { - return nil - } - out := new(SubnetRequest) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetResult) DeepCopyInto(out *SubnetResult) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResult. -func (in *SubnetResult) DeepCopy() *SubnetResult { - if in == nil { - return nil - } - out := new(SubnetResult) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetSet) DeepCopyInto(out *SubnetSet) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -1146,8 +1042,7 @@ func (in *SubnetSetList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetSetSpec) DeepCopyInto(out *SubnetSetSpec) { *out = *in - out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) + out.DHCPConfig = in.DHCPConfig } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetSpec. @@ -1197,8 +1092,7 @@ func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { *out = make([]string, len(*in)) copy(*out, *in) } - out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) + out.DHCPConfig = in.DHCPConfig } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. @@ -1214,8 +1108,18 @@ func (in *SubnetSpec) DeepCopy() *SubnetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses *out = make([]string, len(*in)) copy(*out, *in) } @@ -1238,33 +1142,6 @@ func (in *SubnetStatus) DeepCopy() *SubnetStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPC) DeepCopyInto(out *VPC) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPC. -func (in *VPC) DeepCopy() *VPC { - if in == nil { - return nil - } - out := new(VPC) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VPC) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VPCInfo) DeepCopyInto(out *VPCInfo) { *out = *in @@ -1280,38 +1157,6 @@ func (in *VPCInfo) DeepCopy() *VPCInfo { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCList) DeepCopyInto(out *VPCList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]VPC, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCList. -func (in *VPCList) DeepCopy() *VPCList { - if in == nil { - return nil - } - out := new(VPCList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VPCList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VPCNetworkConfiguration) DeepCopyInto(out *VPCNetworkConfiguration) { *out = *in @@ -1374,13 +1219,8 @@ func (in *VPCNetworkConfigurationList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VPCNetworkConfigurationSpec) DeepCopyInto(out *VPCNetworkConfigurationSpec) { *out = *in - if in.ExternalIPv4Blocks != nil { - in, out := &in.ExternalIPv4Blocks, &out.ExternalIPv4Blocks - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.PrivateIPv4CIDRs != nil { - in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs + if in.PrivateIPs != nil { + in, out := &in.PrivateIPs, &out.PrivateIPs *out = make([]string, len(*in)) copy(*out, *in) } @@ -1404,6 +1244,13 @@ func (in *VPCNetworkConfigurationStatus) DeepCopyInto(out *VPCNetworkConfigurati *out = make([]VPCInfo, len(*in)) copy(*out, *in) } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationStatus. @@ -1416,26 +1263,11 @@ func (in *VPCNetworkConfigurationStatus) DeepCopy() *VPCNetworkConfigurationStat return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCSpec) DeepCopyInto(out *VPCSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCSpec. -func (in *VPCSpec) DeepCopy() *VPCSpec { - if in == nil { - return nil - } - out := new(VPCSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VPCState) DeepCopyInto(out *VPCState) { *out = *in - if in.PrivateIPv4CIDRs != nil { - in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs + if in.PrivateIPs != nil { + in, out := &in.PrivateIPs, &out.PrivateIPs *out = make([]string, len(*in)) copy(*out, *in) } @@ -1450,30 +1282,3 @@ func (in *VPCState) DeepCopy() *VPCState { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VPCStatus) DeepCopyInto(out *VPCStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.PrivateIPv4CIDRs != nil { - in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCStatus. -func (in *VPCStatus) DeepCopy() *VPCStatus { - if in == nil { - return nil - } - out := new(VPCStatus) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/clean/clean.go b/pkg/clean/clean.go index 50b2f0a64..82e780b87 100644 --- a/pkg/clean/clean.go +++ b/pkg/clean/clean.go @@ -9,23 +9,22 @@ import ( "fmt" "time" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/util/retry" - "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ippool" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/securitypolicy" sr "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/staticroute" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnet" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnetport" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" -) -var log = logger.Log + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/retry" +) var Backoff = wait.Backoff{ Steps: 12, @@ -44,7 +43,14 @@ var Backoff = wait.Backoff{ // GetNSXClientFailed indicate that could not retrieve nsx client to perform cleanup operation // InitCleanupServiceFailed indicate that error happened when trying to initialize cleanup service // CleanupResourceFailed indicate that the cleanup operation failed at some services, the detailed will in the service logs -func Clean(ctx context.Context, cf *config.NSXOperatorConfig) error { +func Clean(ctx context.Context, cf *config.NSXOperatorConfig, log *logr.Logger, debug bool, logLevel int) error { + // Clean needs to support many instances which each have its own logger + if log == nil { + logg := logger.ZapLogger(debug, logLevel) + log = &logg + } + logger.InitLog(log) + log.Info("starting NSX cleanup") if err := cf.ValidateConfigFromCmd(); err != nil { return errors.Join(nsxutil.ValidationFailed, err) @@ -53,9 +59,32 @@ func Clean(ctx context.Context, cf *config.NSXOperatorConfig) error { if nsxClient == nil { return nsxutil.GetNSXClientFailed } - if cleanupService, err := InitializeCleanupService(cf, nsxClient); err != nil { - return errors.Join(nsxutil.InitCleanupServiceFailed, err) - } else if cleanupService.err != nil { + // add timeout for initialization + errChan := make(chan error) + var cleanupService *CleanupService + var err error + go func() { + cleanupService, err = InitializeCleanupService(cf, nsxClient) + errChan <- err + }() + + retriable := func(err error) bool { + if err != nil && !errors.As(err, &nsxutil.TimeoutFailed) { + log.Info("retrying to clean up NSX resources", "error", err) + return true + } + return false + } + + select { + case err := <-errChan: + if err != nil { + return errors.Join(nsxutil.InitCleanupServiceFailed, err) + } + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + } + if cleanupService.err != nil { return errors.Join(nsxutil.InitCleanupServiceFailed, cleanupService.err) } else { for _, clean := range cleanupService.cleans { @@ -72,7 +101,7 @@ func Clean(ctx context.Context, cf *config.NSXOperatorConfig) error { } return false }, func() error { - if err := CleanDLB(ctx, nsxClient.Cluster, cf); err != nil { + if err := CleanDLB(ctx, nsxClient.Cluster, cf, log); err != nil { return fmt.Errorf("failed to clean up specific resource: %w", err) } return nil @@ -84,14 +113,6 @@ func Clean(ctx context.Context, cf *config.NSXOperatorConfig) error { return nil } -func retriable(err error) bool { - if err != nil && !errors.As(err, &nsxutil.TimeoutFailed) { - log.Info("retrying to clean up NSX resources", "error", err) - return true - } - return false -} - func wrapCleanFunc(ctx context.Context, clean cleanup) func() error { return func() error { if err := clean.Cleanup(ctx); err != nil { @@ -124,12 +145,6 @@ func InitializeCleanupService(cf *config.NSXOperatorConfig, nsxClient *nsx.Clien return securitypolicy.InitializeSecurityPolicy(service, vpcService) } } - wrapInitializeIPPool := func(service common.Service) cleanupFunc { - return func() (cleanup, error) { - return ippool.InitializeIPPool(service, vpcService) - } - } - wrapInitializeVPC := func(service common.Service) cleanupFunc { return func() (cleanup, error) { return vpcService, vpcErr @@ -147,13 +162,18 @@ func InitializeCleanupService(cf *config.NSXOperatorConfig, nsxClient *nsx.Clien return subnetport.InitializeSubnetPort(service) } } + wrapInitializeIPAddressAllocation := func(service common.Service) cleanupFunc { + return func() (cleanup, error) { + return ipaddressallocation.InitializeIPAddressAllocation(service, vpcService, true) + } + } // TODO: initialize other CR services cleanupService = cleanupService. AddCleanupService(wrapInitializeSubnetPort(commonService)). AddCleanupService(wrapInitializeSubnetService(commonService)). AddCleanupService(wrapInitializeSecurityPolicy(commonService)). - AddCleanupService(wrapInitializeIPPool(commonService)). AddCleanupService(wrapInitializeStaticRoute(commonService)). + AddCleanupService(wrapInitializeIPAddressAllocation(commonService)). AddCleanupService(wrapInitializeVPC(commonService)) return cleanupService, nil diff --git a/pkg/clean/clean_dlb.go b/pkg/clean/clean_dlb.go index a4f1b577c..f29e8ed62 100644 --- a/pkg/clean/clean_dlb.go +++ b/pkg/clean/clean_dlb.go @@ -10,6 +10,8 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" + + "github.com/go-logr/logr" ) type ( @@ -63,7 +65,7 @@ func httpQueryDLBResources(cluster *nsx.Cluster, cf *config.NSXOperatorConfig, r return resourcePath, nil } -func CleanDLB(ctx context.Context, cluster *nsx.Cluster, cf *config.NSXOperatorConfig) error { +func CleanDLB(ctx context.Context, cluster *nsx.Cluster, cf *config.NSXOperatorConfig, log *logr.Logger) error { log.Info("Deleting DLB resources started") resources := []string{"Group", "LBVirtualServer", "LBService", "LBPool", "LBCookiePersistenceProfile"} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index acd4d8b9d..4c3a9cbc0 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,8 +9,7 @@ import ( "fmt" "net/http" - nsxv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1" - nsxv1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/vpc/v1alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -18,25 +17,18 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface - NsxV1alpha1() nsxv1alpha1.NsxV1alpha1Interface - NsxV1alpha2() nsxv1alpha2.NsxV1alpha2Interface + CrdV1alpha1() crdv1alpha1.CrdV1alpha1Interface } // Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient - nsxV1alpha1 *nsxv1alpha1.NsxV1alpha1Client - nsxV1alpha2 *nsxv1alpha2.NsxV1alpha2Client + crdV1alpha1 *crdv1alpha1.CrdV1alpha1Client } -// NsxV1alpha1 retrieves the NsxV1alpha1Client -func (c *Clientset) NsxV1alpha1() nsxv1alpha1.NsxV1alpha1Interface { - return c.nsxV1alpha1 -} - -// NsxV1alpha2 retrieves the NsxV1alpha2Client -func (c *Clientset) NsxV1alpha2() nsxv1alpha2.NsxV1alpha2Interface { - return c.nsxV1alpha2 +// CrdV1alpha1 retrieves the CrdV1alpha1Client +func (c *Clientset) CrdV1alpha1() crdv1alpha1.CrdV1alpha1Interface { + return c.crdV1alpha1 } // Discovery retrieves the DiscoveryClient @@ -83,11 +75,7 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, var cs Clientset var err error - cs.nsxV1alpha1, err = nsxv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) - if err != nil { - return nil, err - } - cs.nsxV1alpha2, err = nsxv1alpha2.NewForConfigAndClient(&configShallowCopy, httpClient) + cs.crdV1alpha1, err = crdv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } @@ -112,8 +100,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset - cs.nsxV1alpha1 = nsxv1alpha1.New(c) - cs.nsxV1alpha2 = nsxv1alpha2.New(c) + cs.crdV1alpha1 = crdv1alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 73d4d324a..aedabae5d 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -7,10 +7,8 @@ package fake import ( clientset "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" - nsxv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1" - fakensxv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake" - nsxv1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2" - fakensxv1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/vpc/v1alpha1" + fakecrdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -68,12 +66,7 @@ var ( _ testing.FakeClient = &Clientset{} ) -// NsxV1alpha1 retrieves the NsxV1alpha1Client -func (c *Clientset) NsxV1alpha1() nsxv1alpha1.NsxV1alpha1Interface { - return &fakensxv1alpha1.FakeNsxV1alpha1{Fake: &c.Fake} -} - -// NsxV1alpha2 retrieves the NsxV1alpha2Client -func (c *Clientset) NsxV1alpha2() nsxv1alpha2.NsxV1alpha2Interface { - return &fakensxv1alpha2.FakeNsxV1alpha2{Fake: &c.Fake} +// CrdV1alpha1 retrieves the CrdV1alpha1Client +func (c *Clientset) CrdV1alpha1() crdv1alpha1.CrdV1alpha1Interface { + return &fakecrdv1alpha1.FakeCrdV1alpha1{Fake: &c.Fake} } diff --git a/pkg/client/clientset/versioned/fake/doc.go b/pkg/client/clientset/versioned/fake/doc.go index 497823177..c327dc2c8 100644 --- a/pkg/client/clientset/versioned/fake/doc.go +++ b/pkg/client/clientset/versioned/fake/doc.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 8b9c91210..e86bbfdb2 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -6,8 +6,7 @@ package fake import ( - nsxv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - nsxv1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -19,8 +18,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ - nsxv1alpha1.AddToScheme, - nsxv1alpha2.AddToScheme, + crdv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/scheme/doc.go b/pkg/client/clientset/versioned/scheme/doc.go index b4cbd389f..c1674626a 100644 --- a/pkg/client/clientset/versioned/scheme/doc.go +++ b/pkg/client/clientset/versioned/scheme/doc.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 52b9ff6c9..27b66fddf 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -6,8 +6,7 @@ package scheme import ( - nsxv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - nsxv1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -19,8 +18,7 @@ var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ - nsxv1alpha1.AddToScheme, - nsxv1alpha2.AddToScheme, + crdv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/doc.go deleted file mode 100644 index f7c0364c0..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ippool.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ippool.go deleted file mode 100644 index 578c05b40..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ippool.go +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeIPPools implements IPPoolInterface -type FakeIPPools struct { - Fake *FakeNsxV1alpha1 - ns string -} - -var ippoolsResource = v1alpha1.SchemeGroupVersion.WithResource("ippools") - -var ippoolsKind = v1alpha1.SchemeGroupVersion.WithKind("IPPool") - -// Get takes name of the iPPool, and returns the corresponding iPPool object, and an error if there is any. -func (c *FakeIPPools) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(ippoolsResource, c.ns, name), &v1alpha1.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.IPPool), err -} - -// List takes label and field selectors, and returns the list of IPPools that match those selectors. -func (c *FakeIPPools) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPPoolList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(ippoolsResource, ippoolsKind, c.ns, opts), &v1alpha1.IPPoolList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.IPPoolList{ListMeta: obj.(*v1alpha1.IPPoolList).ListMeta} - for _, item := range obj.(*v1alpha1.IPPoolList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested iPPools. -func (c *FakeIPPools) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(ippoolsResource, c.ns, opts)) - -} - -// Create takes the representation of a iPPool and creates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *FakeIPPools) Create(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.CreateOptions) (result *v1alpha1.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(ippoolsResource, c.ns, iPPool), &v1alpha1.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.IPPool), err -} - -// Update takes the representation of a iPPool and updates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *FakeIPPools) Update(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.UpdateOptions) (result *v1alpha1.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(ippoolsResource, c.ns, iPPool), &v1alpha1.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.IPPool), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeIPPools) UpdateStatus(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.UpdateOptions) (*v1alpha1.IPPool, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(ippoolsResource, "status", c.ns, iPPool), &v1alpha1.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.IPPool), err -} - -// Delete takes name of the iPPool and deletes it. Returns an error if one occurs. -func (c *FakeIPPools) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(ippoolsResource, c.ns, name, opts), &v1alpha1.IPPool{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeIPPools) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(ippoolsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.IPPoolList{}) - return err -} - -// Patch applies the patch and returns the patched iPPool. -func (c *FakeIPPools) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(ippoolsResource, c.ns, name, pt, data, subresources...), &v1alpha1.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.IPPool), err -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go deleted file mode 100644 index f82bc1e54..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1" - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" -) - -type FakeNsxV1alpha1 struct { - *testing.Fake -} - -func (c *FakeNsxV1alpha1) IPPools(namespace string) v1alpha1.IPPoolInterface { - return &FakeIPPools{c, namespace} -} - -func (c *FakeNsxV1alpha1) NSXServiceAccounts(namespace string) v1alpha1.NSXServiceAccountInterface { - return &FakeNSXServiceAccounts{c, namespace} -} - -func (c *FakeNsxV1alpha1) NetworkInfos(namespace string) v1alpha1.NetworkInfoInterface { - return &FakeNetworkInfos{c, namespace} -} - -func (c *FakeNsxV1alpha1) SecurityPolicies(namespace string) v1alpha1.SecurityPolicyInterface { - return &FakeSecurityPolicies{c, namespace} -} - -func (c *FakeNsxV1alpha1) StaticRoutes(namespace string) v1alpha1.StaticRouteInterface { - return &FakeStaticRoutes{c, namespace} -} - -func (c *FakeNsxV1alpha1) Subnets(namespace string) v1alpha1.SubnetInterface { - return &FakeSubnets{c, namespace} -} - -func (c *FakeNsxV1alpha1) SubnetPorts(namespace string) v1alpha1.SubnetPortInterface { - return &FakeSubnetPorts{c, namespace} -} - -func (c *FakeNsxV1alpha1) SubnetSets(namespace string) v1alpha1.SubnetSetInterface { - return &FakeSubnetSets{c, namespace} -} - -func (c *FakeNsxV1alpha1) VPCs(namespace string) v1alpha1.VPCInterface { - return &FakeVPCs{c, namespace} -} - -func (c *FakeNsxV1alpha1) VPCNetworkConfigurations() v1alpha1.VPCNetworkConfigurationInterface { - return &FakeVPCNetworkConfigurations{c} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeNsxV1alpha1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsxserviceaccount.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsxserviceaccount.go deleted file mode 100644 index ec092ee4d..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsxserviceaccount.go +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeNSXServiceAccounts implements NSXServiceAccountInterface -type FakeNSXServiceAccounts struct { - Fake *FakeNsxV1alpha1 - ns string -} - -var nsxserviceaccountsResource = v1alpha1.SchemeGroupVersion.WithResource("nsxserviceaccounts") - -var nsxserviceaccountsKind = v1alpha1.SchemeGroupVersion.WithKind("NSXServiceAccount") - -// Get takes name of the nSXServiceAccount, and returns the corresponding nSXServiceAccount object, and an error if there is any. -func (c *FakeNSXServiceAccounts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NSXServiceAccount, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(nsxserviceaccountsResource, c.ns, name), &v1alpha1.NSXServiceAccount{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.NSXServiceAccount), err -} - -// List takes label and field selectors, and returns the list of NSXServiceAccounts that match those selectors. -func (c *FakeNSXServiceAccounts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NSXServiceAccountList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(nsxserviceaccountsResource, nsxserviceaccountsKind, c.ns, opts), &v1alpha1.NSXServiceAccountList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.NSXServiceAccountList{ListMeta: obj.(*v1alpha1.NSXServiceAccountList).ListMeta} - for _, item := range obj.(*v1alpha1.NSXServiceAccountList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested nSXServiceAccounts. -func (c *FakeNSXServiceAccounts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(nsxserviceaccountsResource, c.ns, opts)) - -} - -// Create takes the representation of a nSXServiceAccount and creates it. Returns the server's representation of the nSXServiceAccount, and an error, if there is any. -func (c *FakeNSXServiceAccounts) Create(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.CreateOptions) (result *v1alpha1.NSXServiceAccount, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(nsxserviceaccountsResource, c.ns, nSXServiceAccount), &v1alpha1.NSXServiceAccount{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.NSXServiceAccount), err -} - -// Update takes the representation of a nSXServiceAccount and updates it. Returns the server's representation of the nSXServiceAccount, and an error, if there is any. -func (c *FakeNSXServiceAccounts) Update(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.UpdateOptions) (result *v1alpha1.NSXServiceAccount, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(nsxserviceaccountsResource, c.ns, nSXServiceAccount), &v1alpha1.NSXServiceAccount{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.NSXServiceAccount), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeNSXServiceAccounts) UpdateStatus(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.UpdateOptions) (*v1alpha1.NSXServiceAccount, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(nsxserviceaccountsResource, "status", c.ns, nSXServiceAccount), &v1alpha1.NSXServiceAccount{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.NSXServiceAccount), err -} - -// Delete takes name of the nSXServiceAccount and deletes it. Returns an error if one occurs. -func (c *FakeNSXServiceAccounts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(nsxserviceaccountsResource, c.ns, name, opts), &v1alpha1.NSXServiceAccount{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeNSXServiceAccounts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(nsxserviceaccountsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.NSXServiceAccountList{}) - return err -} - -// Patch applies the patch and returns the patched nSXServiceAccount. -func (c *FakeNSXServiceAccounts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NSXServiceAccount, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(nsxserviceaccountsResource, c.ns, name, pt, data, subresources...), &v1alpha1.NSXServiceAccount{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.NSXServiceAccount), err -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_vpc.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_vpc.go deleted file mode 100644 index 0899713ad..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_vpc.go +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeVPCs implements VPCInterface -type FakeVPCs struct { - Fake *FakeNsxV1alpha1 - ns string -} - -var vpcsResource = v1alpha1.SchemeGroupVersion.WithResource("vpcs") - -var vpcsKind = v1alpha1.SchemeGroupVersion.WithKind("VPC") - -// Get takes name of the vPC, and returns the corresponding vPC object, and an error if there is any. -func (c *FakeVPCs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VPC, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(vpcsResource, c.ns, name), &v1alpha1.VPC{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.VPC), err -} - -// List takes label and field selectors, and returns the list of VPCs that match those selectors. -func (c *FakeVPCs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VPCList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(vpcsResource, vpcsKind, c.ns, opts), &v1alpha1.VPCList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.VPCList{ListMeta: obj.(*v1alpha1.VPCList).ListMeta} - for _, item := range obj.(*v1alpha1.VPCList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested vPCs. -func (c *FakeVPCs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(vpcsResource, c.ns, opts)) - -} - -// Create takes the representation of a vPC and creates it. Returns the server's representation of the vPC, and an error, if there is any. -func (c *FakeVPCs) Create(ctx context.Context, vPC *v1alpha1.VPC, opts v1.CreateOptions) (result *v1alpha1.VPC, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(vpcsResource, c.ns, vPC), &v1alpha1.VPC{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.VPC), err -} - -// Update takes the representation of a vPC and updates it. Returns the server's representation of the vPC, and an error, if there is any. -func (c *FakeVPCs) Update(ctx context.Context, vPC *v1alpha1.VPC, opts v1.UpdateOptions) (result *v1alpha1.VPC, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(vpcsResource, c.ns, vPC), &v1alpha1.VPC{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.VPC), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeVPCs) UpdateStatus(ctx context.Context, vPC *v1alpha1.VPC, opts v1.UpdateOptions) (*v1alpha1.VPC, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(vpcsResource, "status", c.ns, vPC), &v1alpha1.VPC{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.VPC), err -} - -// Delete takes name of the vPC and deletes it. Returns an error if one occurs. -func (c *FakeVPCs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(vpcsResource, c.ns, name, opts), &v1alpha1.VPC{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeVPCs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(vpcsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.VPCList{}) - return err -} - -// Patch applies the patch and returns the patched vPC. -func (c *FakeVPCs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VPC, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(vpcsResource, c.ns, name, pt, data, subresources...), &v1alpha1.VPC{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.VPC), err -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ippool.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ippool.go deleted file mode 100644 index f9d995fbc..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ippool.go +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// IPPoolsGetter has a method to return a IPPoolInterface. -// A group's client should implement this interface. -type IPPoolsGetter interface { - IPPools(namespace string) IPPoolInterface -} - -// IPPoolInterface has methods to work with IPPool resources. -type IPPoolInterface interface { - Create(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.CreateOptions) (*v1alpha1.IPPool, error) - Update(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.UpdateOptions) (*v1alpha1.IPPool, error) - UpdateStatus(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.UpdateOptions) (*v1alpha1.IPPool, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.IPPool, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.IPPoolList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPPool, err error) - IPPoolExpansion -} - -// iPPools implements IPPoolInterface -type iPPools struct { - client rest.Interface - ns string -} - -// newIPPools returns a IPPools -func newIPPools(c *NsxV1alpha1Client, namespace string) *iPPools { - return &iPPools{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the iPPool, and returns the corresponding iPPool object, and an error if there is any. -func (c *iPPools) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPPool, err error) { - result = &v1alpha1.IPPool{} - err = c.client.Get(). - Namespace(c.ns). - Resource("ippools"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of IPPools that match those selectors. -func (c *iPPools) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPPoolList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.IPPoolList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested iPPools. -func (c *iPPools) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a iPPool and creates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *iPPools) Create(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.CreateOptions) (result *v1alpha1.IPPool, err error) { - result = &v1alpha1.IPPool{} - err = c.client.Post(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(iPPool). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a iPPool and updates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *iPPools) Update(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.UpdateOptions) (result *v1alpha1.IPPool, err error) { - result = &v1alpha1.IPPool{} - err = c.client.Put(). - Namespace(c.ns). - Resource("ippools"). - Name(iPPool.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(iPPool). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *iPPools) UpdateStatus(ctx context.Context, iPPool *v1alpha1.IPPool, opts v1.UpdateOptions) (result *v1alpha1.IPPool, err error) { - result = &v1alpha1.IPPool{} - err = c.client.Put(). - Namespace(c.ns). - Resource("ippools"). - Name(iPPool.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(iPPool). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the iPPool and deletes it. Returns an error if one occurs. -func (c *iPPools) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("ippools"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *iPPools) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched iPPool. -func (c *iPPools) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPPool, err error) { - result = &v1alpha1.IPPool{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("ippools"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsxserviceaccount.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsxserviceaccount.go deleted file mode 100644 index 4cf6075b5..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsxserviceaccount.go +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// NSXServiceAccountsGetter has a method to return a NSXServiceAccountInterface. -// A group's client should implement this interface. -type NSXServiceAccountsGetter interface { - NSXServiceAccounts(namespace string) NSXServiceAccountInterface -} - -// NSXServiceAccountInterface has methods to work with NSXServiceAccount resources. -type NSXServiceAccountInterface interface { - Create(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.CreateOptions) (*v1alpha1.NSXServiceAccount, error) - Update(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.UpdateOptions) (*v1alpha1.NSXServiceAccount, error) - UpdateStatus(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.UpdateOptions) (*v1alpha1.NSXServiceAccount, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NSXServiceAccount, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NSXServiceAccountList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NSXServiceAccount, err error) - NSXServiceAccountExpansion -} - -// nSXServiceAccounts implements NSXServiceAccountInterface -type nSXServiceAccounts struct { - client rest.Interface - ns string -} - -// newNSXServiceAccounts returns a NSXServiceAccounts -func newNSXServiceAccounts(c *NsxV1alpha1Client, namespace string) *nSXServiceAccounts { - return &nSXServiceAccounts{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the nSXServiceAccount, and returns the corresponding nSXServiceAccount object, and an error if there is any. -func (c *nSXServiceAccounts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NSXServiceAccount, err error) { - result = &v1alpha1.NSXServiceAccount{} - err = c.client.Get(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of NSXServiceAccounts that match those selectors. -func (c *nSXServiceAccounts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NSXServiceAccountList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.NSXServiceAccountList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested nSXServiceAccounts. -func (c *nSXServiceAccounts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a nSXServiceAccount and creates it. Returns the server's representation of the nSXServiceAccount, and an error, if there is any. -func (c *nSXServiceAccounts) Create(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.CreateOptions) (result *v1alpha1.NSXServiceAccount, err error) { - result = &v1alpha1.NSXServiceAccount{} - err = c.client.Post(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nSXServiceAccount). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a nSXServiceAccount and updates it. Returns the server's representation of the nSXServiceAccount, and an error, if there is any. -func (c *nSXServiceAccounts) Update(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.UpdateOptions) (result *v1alpha1.NSXServiceAccount, err error) { - result = &v1alpha1.NSXServiceAccount{} - err = c.client.Put(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - Name(nSXServiceAccount.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nSXServiceAccount). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *nSXServiceAccounts) UpdateStatus(ctx context.Context, nSXServiceAccount *v1alpha1.NSXServiceAccount, opts v1.UpdateOptions) (result *v1alpha1.NSXServiceAccount, err error) { - result = &v1alpha1.NSXServiceAccount{} - err = c.client.Put(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - Name(nSXServiceAccount.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nSXServiceAccount). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the nSXServiceAccount and deletes it. Returns an error if one occurs. -func (c *nSXServiceAccounts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *nSXServiceAccounts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched nSXServiceAccount. -func (c *nSXServiceAccounts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NSXServiceAccount, err error) { - result = &v1alpha1.NSXServiceAccount{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("nsxserviceaccounts"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/vpc.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/vpc.go deleted file mode 100644 index a5ff30581..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/vpc.go +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// VPCsGetter has a method to return a VPCInterface. -// A group's client should implement this interface. -type VPCsGetter interface { - VPCs(namespace string) VPCInterface -} - -// VPCInterface has methods to work with VPC resources. -type VPCInterface interface { - Create(ctx context.Context, vPC *v1alpha1.VPC, opts v1.CreateOptions) (*v1alpha1.VPC, error) - Update(ctx context.Context, vPC *v1alpha1.VPC, opts v1.UpdateOptions) (*v1alpha1.VPC, error) - UpdateStatus(ctx context.Context, vPC *v1alpha1.VPC, opts v1.UpdateOptions) (*v1alpha1.VPC, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.VPC, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.VPCList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VPC, err error) - VPCExpansion -} - -// vPCs implements VPCInterface -type vPCs struct { - client rest.Interface - ns string -} - -// newVPCs returns a VPCs -func newVPCs(c *NsxV1alpha1Client, namespace string) *vPCs { - return &vPCs{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the vPC, and returns the corresponding vPC object, and an error if there is any. -func (c *vPCs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VPC, err error) { - result = &v1alpha1.VPC{} - err = c.client.Get(). - Namespace(c.ns). - Resource("vpcs"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of VPCs that match those selectors. -func (c *vPCs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VPCList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.VPCList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("vpcs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested vPCs. -func (c *vPCs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("vpcs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a vPC and creates it. Returns the server's representation of the vPC, and an error, if there is any. -func (c *vPCs) Create(ctx context.Context, vPC *v1alpha1.VPC, opts v1.CreateOptions) (result *v1alpha1.VPC, err error) { - result = &v1alpha1.VPC{} - err = c.client.Post(). - Namespace(c.ns). - Resource("vpcs"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(vPC). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a vPC and updates it. Returns the server's representation of the vPC, and an error, if there is any. -func (c *vPCs) Update(ctx context.Context, vPC *v1alpha1.VPC, opts v1.UpdateOptions) (result *v1alpha1.VPC, err error) { - result = &v1alpha1.VPC{} - err = c.client.Put(). - Namespace(c.ns). - Resource("vpcs"). - Name(vPC.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(vPC). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *vPCs) UpdateStatus(ctx context.Context, vPC *v1alpha1.VPC, opts v1.UpdateOptions) (result *v1alpha1.VPC, err error) { - result = &v1alpha1.VPC{} - err = c.client.Put(). - Namespace(c.ns). - Resource("vpcs"). - Name(vPC.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(vPC). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the vPC and deletes it. Returns an error if one occurs. -func (c *vPCs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("vpcs"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *vPCs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("vpcs"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched vPC. -func (c *vPCs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VPC, err error) { - result = &v1alpha1.VPC{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("vpcs"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/doc.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/doc.go deleted file mode 100644 index dee26b9f8..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1alpha2 diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/fake_ippool.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/fake_ippool.go deleted file mode 100644 index d442c1445..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/fake_ippool.go +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeIPPools implements IPPoolInterface -type FakeIPPools struct { - Fake *FakeNsxV1alpha2 - ns string -} - -var ippoolsResource = v1alpha2.SchemeGroupVersion.WithResource("ippools") - -var ippoolsKind = v1alpha2.SchemeGroupVersion.WithKind("IPPool") - -// Get takes name of the iPPool, and returns the corresponding iPPool object, and an error if there is any. -func (c *FakeIPPools) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(ippoolsResource, c.ns, name), &v1alpha2.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha2.IPPool), err -} - -// List takes label and field selectors, and returns the list of IPPools that match those selectors. -func (c *FakeIPPools) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.IPPoolList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(ippoolsResource, ippoolsKind, c.ns, opts), &v1alpha2.IPPoolList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha2.IPPoolList{ListMeta: obj.(*v1alpha2.IPPoolList).ListMeta} - for _, item := range obj.(*v1alpha2.IPPoolList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested iPPools. -func (c *FakeIPPools) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(ippoolsResource, c.ns, opts)) - -} - -// Create takes the representation of a iPPool and creates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *FakeIPPools) Create(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.CreateOptions) (result *v1alpha2.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(ippoolsResource, c.ns, iPPool), &v1alpha2.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha2.IPPool), err -} - -// Update takes the representation of a iPPool and updates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *FakeIPPools) Update(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.UpdateOptions) (result *v1alpha2.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(ippoolsResource, c.ns, iPPool), &v1alpha2.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha2.IPPool), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeIPPools) UpdateStatus(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.UpdateOptions) (*v1alpha2.IPPool, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(ippoolsResource, "status", c.ns, iPPool), &v1alpha2.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha2.IPPool), err -} - -// Delete takes name of the iPPool and deletes it. Returns an error if one occurs. -func (c *FakeIPPools) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(ippoolsResource, c.ns, name, opts), &v1alpha2.IPPool{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeIPPools) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(ippoolsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha2.IPPoolList{}) - return err -} - -// Patch applies the patch and returns the patched iPPool. -func (c *FakeIPPools) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.IPPool, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(ippoolsResource, c.ns, name, pt, data, subresources...), &v1alpha2.IPPool{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha2.IPPool), err -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/fake_nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/fake_nsx.vmware.com_client.go deleted file mode 100644 index d75ec38c6..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/fake_nsx.vmware.com_client.go +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2" - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" -) - -type FakeNsxV1alpha2 struct { - *testing.Fake -} - -func (c *FakeNsxV1alpha2) IPPools(namespace string) v1alpha2.IPPoolInterface { - return &FakeIPPools{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeNsxV1alpha2) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/generated_expansion.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/generated_expansion.go deleted file mode 100644 index 39b9a5e25..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/generated_expansion.go +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha2 - -type IPPoolExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/ippool.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/ippool.go deleted file mode 100644 index 230300c9a..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/ippool.go +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - "context" - "time" - - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" - scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// IPPoolsGetter has a method to return a IPPoolInterface. -// A group's client should implement this interface. -type IPPoolsGetter interface { - IPPools(namespace string) IPPoolInterface -} - -// IPPoolInterface has methods to work with IPPool resources. -type IPPoolInterface interface { - Create(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.CreateOptions) (*v1alpha2.IPPool, error) - Update(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.UpdateOptions) (*v1alpha2.IPPool, error) - UpdateStatus(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.UpdateOptions) (*v1alpha2.IPPool, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha2.IPPool, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha2.IPPoolList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.IPPool, err error) - IPPoolExpansion -} - -// iPPools implements IPPoolInterface -type iPPools struct { - client rest.Interface - ns string -} - -// newIPPools returns a IPPools -func newIPPools(c *NsxV1alpha2Client, namespace string) *iPPools { - return &iPPools{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the iPPool, and returns the corresponding iPPool object, and an error if there is any. -func (c *iPPools) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.IPPool, err error) { - result = &v1alpha2.IPPool{} - err = c.client.Get(). - Namespace(c.ns). - Resource("ippools"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of IPPools that match those selectors. -func (c *iPPools) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.IPPoolList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha2.IPPoolList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested iPPools. -func (c *iPPools) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a iPPool and creates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *iPPools) Create(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.CreateOptions) (result *v1alpha2.IPPool, err error) { - result = &v1alpha2.IPPool{} - err = c.client.Post(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(iPPool). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a iPPool and updates it. Returns the server's representation of the iPPool, and an error, if there is any. -func (c *iPPools) Update(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.UpdateOptions) (result *v1alpha2.IPPool, err error) { - result = &v1alpha2.IPPool{} - err = c.client.Put(). - Namespace(c.ns). - Resource("ippools"). - Name(iPPool.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(iPPool). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *iPPools) UpdateStatus(ctx context.Context, iPPool *v1alpha2.IPPool, opts v1.UpdateOptions) (result *v1alpha2.IPPool, err error) { - result = &v1alpha2.IPPool{} - err = c.client.Put(). - Namespace(c.ns). - Resource("ippools"). - Name(iPPool.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(iPPool). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the iPPool and deletes it. Returns an error if one occurs. -func (c *iPPools) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("ippools"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *iPPools) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("ippools"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched iPPool. -func (c *iPPools) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.IPPool, err error) { - result = &v1alpha2.IPPool{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("ippools"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/nsx.vmware.com_client.go deleted file mode 100644 index 29e558aa9..000000000 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/nsx.vmware.com_client.go +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - "net/http" - - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" - "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" - rest "k8s.io/client-go/rest" -) - -type NsxV1alpha2Interface interface { - RESTClient() rest.Interface - IPPoolsGetter -} - -// NsxV1alpha2Client is used to interact with features provided by the nsx.vmware.com group. -type NsxV1alpha2Client struct { - restClient rest.Interface -} - -func (c *NsxV1alpha2Client) IPPools(namespace string) IPPoolInterface { - return newIPPools(c, namespace) -} - -// NewForConfig creates a new NsxV1alpha2Client for the given config. -// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), -// where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*NsxV1alpha2Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - httpClient, err := rest.HTTPClientFor(&config) - if err != nil { - return nil, err - } - return NewForConfigAndClient(&config, httpClient) -} - -// NewForConfigAndClient creates a new NsxV1alpha2Client for the given config and http client. -// Note the http client provided takes precedence over the configured transport values. -func NewForConfigAndClient(c *rest.Config, h *http.Client) (*NsxV1alpha2Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientForConfigAndClient(&config, h) - if err != nil { - return nil, err - } - return &NsxV1alpha2Client{client}, nil -} - -// NewForConfigOrDie creates a new NsxV1alpha2Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *NsxV1alpha2Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new NsxV1alpha2Client for the given RESTClient. -func New(c rest.Interface) *NsxV1alpha2Client { - return &NsxV1alpha2Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1alpha2.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *NsxV1alpha2Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/addressbinding.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/addressbinding.go new file mode 100644 index 000000000..499a2b692 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/addressbinding.go @@ -0,0 +1,182 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// AddressBindingsGetter has a method to return a AddressBindingInterface. +// A group's client should implement this interface. +type AddressBindingsGetter interface { + AddressBindings(namespace string) AddressBindingInterface +} + +// AddressBindingInterface has methods to work with AddressBinding resources. +type AddressBindingInterface interface { + Create(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.CreateOptions) (*v1alpha1.AddressBinding, error) + Update(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (*v1alpha1.AddressBinding, error) + UpdateStatus(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (*v1alpha1.AddressBinding, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.AddressBinding, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.AddressBindingList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.AddressBinding, err error) + AddressBindingExpansion +} + +// addressBindings implements AddressBindingInterface +type addressBindings struct { + client rest.Interface + ns string +} + +// newAddressBindings returns a AddressBindings +func newAddressBindings(c *CrdV1alpha1Client, namespace string) *addressBindings { + return &addressBindings{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the addressBinding, and returns the corresponding addressBinding object, and an error if there is any. +func (c *addressBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Get(). + Namespace(c.ns). + Resource("addressbindings"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of AddressBindings that match those selectors. +func (c *addressBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.AddressBindingList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.AddressBindingList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested addressBindings. +func (c *addressBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a addressBinding and creates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *addressBindings) Create(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.CreateOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Post(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(addressBinding). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a addressBinding and updates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *addressBindings) Update(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Put(). + Namespace(c.ns). + Resource("addressbindings"). + Name(addressBinding.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(addressBinding). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *addressBindings) UpdateStatus(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Put(). + Namespace(c.ns). + Resource("addressbindings"). + Name(addressBinding.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(addressBinding). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the addressBinding and deletes it. Returns an error if one occurs. +func (c *addressBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("addressbindings"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *addressBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched addressBinding. +func (c *addressBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("addressbindings"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/doc.go similarity index 75% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/doc.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/doc.go index 7e1618024..b37a67a0a 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/doc.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/doc.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/doc.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/doc.go similarity index 74% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/doc.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/doc.go index f7c0364c0..e6c76bef4 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha2/fake/doc.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/doc.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_addressbinding.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_addressbinding.go new file mode 100644 index 000000000..0d0504d33 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_addressbinding.go @@ -0,0 +1,128 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeAddressBindings implements AddressBindingInterface +type FakeAddressBindings struct { + Fake *FakeCrdV1alpha1 + ns string +} + +var addressbindingsResource = v1alpha1.SchemeGroupVersion.WithResource("addressbindings") + +var addressbindingsKind = v1alpha1.SchemeGroupVersion.WithKind("AddressBinding") + +// Get takes name of the addressBinding, and returns the corresponding addressBinding object, and an error if there is any. +func (c *FakeAddressBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(addressbindingsResource, c.ns, name), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// List takes label and field selectors, and returns the list of AddressBindings that match those selectors. +func (c *FakeAddressBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.AddressBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(addressbindingsResource, addressbindingsKind, c.ns, opts), &v1alpha1.AddressBindingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.AddressBindingList{ListMeta: obj.(*v1alpha1.AddressBindingList).ListMeta} + for _, item := range obj.(*v1alpha1.AddressBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested addressBindings. +func (c *FakeAddressBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(addressbindingsResource, c.ns, opts)) + +} + +// Create takes the representation of a addressBinding and creates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *FakeAddressBindings) Create(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.CreateOptions) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(addressbindingsResource, c.ns, addressBinding), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// Update takes the representation of a addressBinding and updates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *FakeAddressBindings) Update(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(addressbindingsResource, c.ns, addressBinding), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeAddressBindings) UpdateStatus(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (*v1alpha1.AddressBinding, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(addressbindingsResource, "status", c.ns, addressBinding), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// Delete takes name of the addressBinding and deletes it. Returns an error if one occurs. +func (c *FakeAddressBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(addressbindingsResource, c.ns, name, opts), &v1alpha1.AddressBinding{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeAddressBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(addressbindingsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.AddressBindingList{}) + return err +} + +// Patch applies the patch and returns the patched addressBinding. +func (c *FakeAddressBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(addressbindingsResource, c.ns, name, pt, data, subresources...), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_ipaddressallocation.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_ipaddressallocation.go new file mode 100644 index 000000000..c501fea6e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_ipaddressallocation.go @@ -0,0 +1,128 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeIPAddressAllocations implements IPAddressAllocationInterface +type FakeIPAddressAllocations struct { + Fake *FakeCrdV1alpha1 + ns string +} + +var ipaddressallocationsResource = v1alpha1.SchemeGroupVersion.WithResource("ipaddressallocations") + +var ipaddressallocationsKind = v1alpha1.SchemeGroupVersion.WithKind("IPAddressAllocation") + +// Get takes name of the iPAddressAllocation, and returns the corresponding iPAddressAllocation object, and an error if there is any. +func (c *FakeIPAddressAllocations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(ipaddressallocationsResource, c.ns, name), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// List takes label and field selectors, and returns the list of IPAddressAllocations that match those selectors. +func (c *FakeIPAddressAllocations) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPAddressAllocationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(ipaddressallocationsResource, ipaddressallocationsKind, c.ns, opts), &v1alpha1.IPAddressAllocationList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.IPAddressAllocationList{ListMeta: obj.(*v1alpha1.IPAddressAllocationList).ListMeta} + for _, item := range obj.(*v1alpha1.IPAddressAllocationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested iPAddressAllocations. +func (c *FakeIPAddressAllocations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(ipaddressallocationsResource, c.ns, opts)) + +} + +// Create takes the representation of a iPAddressAllocation and creates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *FakeIPAddressAllocations) Create(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.CreateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(ipaddressallocationsResource, c.ns, iPAddressAllocation), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// Update takes the representation of a iPAddressAllocation and updates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *FakeIPAddressAllocations) Update(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(ipaddressallocationsResource, c.ns, iPAddressAllocation), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeIPAddressAllocations) UpdateStatus(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (*v1alpha1.IPAddressAllocation, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(ipaddressallocationsResource, "status", c.ns, iPAddressAllocation), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// Delete takes name of the iPAddressAllocation and deletes it. Returns an error if one occurs. +func (c *FakeIPAddressAllocations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(ipaddressallocationsResource, c.ns, name, opts), &v1alpha1.IPAddressAllocation{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIPAddressAllocations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(ipaddressallocationsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.IPAddressAllocationList{}) + return err +} + +// Patch applies the patch and returns the patched iPAddressAllocation. +func (c *FakeIPAddressAllocations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ipaddressallocationsResource, c.ns, name, pt, data, subresources...), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_ipblocksinfo.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_ipblocksinfo.go new file mode 100644 index 000000000..a5261db93 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_ipblocksinfo.go @@ -0,0 +1,116 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeIPBlocksInfos implements IPBlocksInfoInterface +type FakeIPBlocksInfos struct { + Fake *FakeCrdV1alpha1 + ns string +} + +var ipblocksinfosResource = v1alpha1.SchemeGroupVersion.WithResource("ipblocksinfos") + +var ipblocksinfosKind = v1alpha1.SchemeGroupVersion.WithKind("IPBlocksInfo") + +// Get takes name of the iPBlocksInfo, and returns the corresponding iPBlocksInfo object, and an error if there is any. +func (c *FakeIPBlocksInfos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPBlocksInfo, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(ipblocksinfosResource, c.ns, name), &v1alpha1.IPBlocksInfo{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPBlocksInfo), err +} + +// List takes label and field selectors, and returns the list of IPBlocksInfos that match those selectors. +func (c *FakeIPBlocksInfos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPBlocksInfoList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(ipblocksinfosResource, ipblocksinfosKind, c.ns, opts), &v1alpha1.IPBlocksInfoList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.IPBlocksInfoList{ListMeta: obj.(*v1alpha1.IPBlocksInfoList).ListMeta} + for _, item := range obj.(*v1alpha1.IPBlocksInfoList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested iPBlocksInfos. +func (c *FakeIPBlocksInfos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(ipblocksinfosResource, c.ns, opts)) + +} + +// Create takes the representation of a iPBlocksInfo and creates it. Returns the server's representation of the iPBlocksInfo, and an error, if there is any. +func (c *FakeIPBlocksInfos) Create(ctx context.Context, iPBlocksInfo *v1alpha1.IPBlocksInfo, opts v1.CreateOptions) (result *v1alpha1.IPBlocksInfo, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(ipblocksinfosResource, c.ns, iPBlocksInfo), &v1alpha1.IPBlocksInfo{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPBlocksInfo), err +} + +// Update takes the representation of a iPBlocksInfo and updates it. Returns the server's representation of the iPBlocksInfo, and an error, if there is any. +func (c *FakeIPBlocksInfos) Update(ctx context.Context, iPBlocksInfo *v1alpha1.IPBlocksInfo, opts v1.UpdateOptions) (result *v1alpha1.IPBlocksInfo, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(ipblocksinfosResource, c.ns, iPBlocksInfo), &v1alpha1.IPBlocksInfo{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPBlocksInfo), err +} + +// Delete takes name of the iPBlocksInfo and deletes it. Returns an error if one occurs. +func (c *FakeIPBlocksInfos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(ipblocksinfosResource, c.ns, name, opts), &v1alpha1.IPBlocksInfo{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIPBlocksInfos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(ipblocksinfosResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.IPBlocksInfoList{}) + return err +} + +// Patch applies the patch and returns the patched iPBlocksInfo. +func (c *FakeIPBlocksInfos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPBlocksInfo, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ipblocksinfosResource, c.ns, name, pt, data, subresources...), &v1alpha1.IPBlocksInfo{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPBlocksInfo), err +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_networkinfo.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_networkinfo.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_networkinfo.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_networkinfo.go index 2bfbcfc19..bcc689b3c 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_networkinfo.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_networkinfo.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeNetworkInfos implements NetworkInfoInterface type FakeNetworkInfos struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 ns string } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_securitypolicy.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_securitypolicy.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_securitypolicy.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_securitypolicy.go index 6f17b5cec..28e9677a1 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_securitypolicy.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_securitypolicy.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeSecurityPolicies implements SecurityPolicyInterface type FakeSecurityPolicies struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 ns string } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_staticroute.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_staticroute.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_staticroute.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_staticroute.go index d6a0a0396..93595beec 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_staticroute.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_staticroute.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeStaticRoutes implements StaticRouteInterface type FakeStaticRoutes struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 ns string } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnet.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnet.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnet.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnet.go index 46984a34d..4e8becc46 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnet.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnet.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeSubnets implements SubnetInterface type FakeSubnets struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 ns string } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnetport.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnetport.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnetport.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnetport.go index e9d418778..6ad4dc104 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnetport.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnetport.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeSubnetPorts implements SubnetPortInterface type FakeSubnetPorts struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 ns string } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnetset.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnetset.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnetset.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnetset.go index 6d0aa0ee7..6642a92cd 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_subnetset.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_subnetset.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeSubnetSets implements SubnetSetInterface type FakeSubnetSets struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 ns string } diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_vpc_client.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_vpc_client.go new file mode 100644 index 000000000..f61b00f3d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_vpc_client.go @@ -0,0 +1,63 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/typed/vpc/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCrdV1alpha1 struct { + *testing.Fake +} + +func (c *FakeCrdV1alpha1) AddressBindings(namespace string) v1alpha1.AddressBindingInterface { + return &FakeAddressBindings{c, namespace} +} + +func (c *FakeCrdV1alpha1) IPAddressAllocations(namespace string) v1alpha1.IPAddressAllocationInterface { + return &FakeIPAddressAllocations{c, namespace} +} + +func (c *FakeCrdV1alpha1) IPBlocksInfos(namespace string) v1alpha1.IPBlocksInfoInterface { + return &FakeIPBlocksInfos{c, namespace} +} + +func (c *FakeCrdV1alpha1) NetworkInfos(namespace string) v1alpha1.NetworkInfoInterface { + return &FakeNetworkInfos{c, namespace} +} + +func (c *FakeCrdV1alpha1) SecurityPolicies(namespace string) v1alpha1.SecurityPolicyInterface { + return &FakeSecurityPolicies{c, namespace} +} + +func (c *FakeCrdV1alpha1) StaticRoutes(namespace string) v1alpha1.StaticRouteInterface { + return &FakeStaticRoutes{c, namespace} +} + +func (c *FakeCrdV1alpha1) Subnets(namespace string) v1alpha1.SubnetInterface { + return &FakeSubnets{c, namespace} +} + +func (c *FakeCrdV1alpha1) SubnetPorts(namespace string) v1alpha1.SubnetPortInterface { + return &FakeSubnetPorts{c, namespace} +} + +func (c *FakeCrdV1alpha1) SubnetSets(namespace string) v1alpha1.SubnetSetInterface { + return &FakeSubnetSets{c, namespace} +} + +func (c *FakeCrdV1alpha1) VPCNetworkConfigurations() v1alpha1.VPCNetworkConfigurationInterface { + return &FakeVPCNetworkConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCrdV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_vpcnetworkconfiguration.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_vpcnetworkconfiguration.go similarity index 97% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_vpcnetworkconfiguration.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_vpcnetworkconfiguration.go index 8b46fccfb..da0fbd0c0 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_vpcnetworkconfiguration.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/fake/fake_vpcnetworkconfiguration.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,7 +8,7 @@ package fake import ( "context" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" @@ -18,7 +18,7 @@ import ( // FakeVPCNetworkConfigurations implements VPCNetworkConfigurationInterface type FakeVPCNetworkConfigurations struct { - Fake *FakeNsxV1alpha1 + Fake *FakeCrdV1alpha1 } var vpcnetworkconfigurationsResource = v1alpha1.SchemeGroupVersion.WithResource("vpcnetworkconfigurations") diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/generated_expansion.go similarity index 68% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/generated_expansion.go index 70b6cc354..113c6070f 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/generated_expansion.go @@ -1,13 +1,15 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. package v1alpha1 -type IPPoolExpansion interface{} +type AddressBindingExpansion interface{} -type NSXServiceAccountExpansion interface{} +type IPAddressAllocationExpansion interface{} + +type IPBlocksInfoExpansion interface{} type NetworkInfoExpansion interface{} @@ -21,6 +23,4 @@ type SubnetPortExpansion interface{} type SubnetSetExpansion interface{} -type VPCExpansion interface{} - type VPCNetworkConfigurationExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/ipaddressallocation.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/ipaddressallocation.go new file mode 100644 index 000000000..75f268ce2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/ipaddressallocation.go @@ -0,0 +1,182 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// IPAddressAllocationsGetter has a method to return a IPAddressAllocationInterface. +// A group's client should implement this interface. +type IPAddressAllocationsGetter interface { + IPAddressAllocations(namespace string) IPAddressAllocationInterface +} + +// IPAddressAllocationInterface has methods to work with IPAddressAllocation resources. +type IPAddressAllocationInterface interface { + Create(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.CreateOptions) (*v1alpha1.IPAddressAllocation, error) + Update(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (*v1alpha1.IPAddressAllocation, error) + UpdateStatus(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (*v1alpha1.IPAddressAllocation, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.IPAddressAllocation, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.IPAddressAllocationList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPAddressAllocation, err error) + IPAddressAllocationExpansion +} + +// iPAddressAllocations implements IPAddressAllocationInterface +type iPAddressAllocations struct { + client rest.Interface + ns string +} + +// newIPAddressAllocations returns a IPAddressAllocations +func newIPAddressAllocations(c *CrdV1alpha1Client, namespace string) *iPAddressAllocations { + return &iPAddressAllocations{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the iPAddressAllocation, and returns the corresponding iPAddressAllocation object, and an error if there is any. +func (c *iPAddressAllocations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Get(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of IPAddressAllocations that match those selectors. +func (c *iPAddressAllocations) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPAddressAllocationList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.IPAddressAllocationList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested iPAddressAllocations. +func (c *iPAddressAllocations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a iPAddressAllocation and creates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *iPAddressAllocations) Create(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.CreateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Post(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPAddressAllocation). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a iPAddressAllocation and updates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *iPAddressAllocations) Update(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(iPAddressAllocation.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPAddressAllocation). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *iPAddressAllocations) UpdateStatus(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(iPAddressAllocation.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPAddressAllocation). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the iPAddressAllocation and deletes it. Returns an error if one occurs. +func (c *iPAddressAllocations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *iPAddressAllocations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched iPAddressAllocation. +func (c *iPAddressAllocations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/vpc/v1alpha1/ipblocksinfo.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/ipblocksinfo.go new file mode 100644 index 000000000..a0eaf084a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/ipblocksinfo.go @@ -0,0 +1,165 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// IPBlocksInfosGetter has a method to return a IPBlocksInfoInterface. +// A group's client should implement this interface. +type IPBlocksInfosGetter interface { + IPBlocksInfos(namespace string) IPBlocksInfoInterface +} + +// IPBlocksInfoInterface has methods to work with IPBlocksInfo resources. +type IPBlocksInfoInterface interface { + Create(ctx context.Context, iPBlocksInfo *v1alpha1.IPBlocksInfo, opts v1.CreateOptions) (*v1alpha1.IPBlocksInfo, error) + Update(ctx context.Context, iPBlocksInfo *v1alpha1.IPBlocksInfo, opts v1.UpdateOptions) (*v1alpha1.IPBlocksInfo, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.IPBlocksInfo, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.IPBlocksInfoList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPBlocksInfo, err error) + IPBlocksInfoExpansion +} + +// iPBlocksInfos implements IPBlocksInfoInterface +type iPBlocksInfos struct { + client rest.Interface + ns string +} + +// newIPBlocksInfos returns a IPBlocksInfos +func newIPBlocksInfos(c *CrdV1alpha1Client, namespace string) *iPBlocksInfos { + return &iPBlocksInfos{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the iPBlocksInfo, and returns the corresponding iPBlocksInfo object, and an error if there is any. +func (c *iPBlocksInfos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPBlocksInfo, err error) { + result = &v1alpha1.IPBlocksInfo{} + err = c.client.Get(). + Namespace(c.ns). + Resource("ipblocksinfos"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of IPBlocksInfos that match those selectors. +func (c *iPBlocksInfos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPBlocksInfoList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.IPBlocksInfoList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("ipblocksinfos"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested iPBlocksInfos. +func (c *iPBlocksInfos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("ipblocksinfos"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a iPBlocksInfo and creates it. Returns the server's representation of the iPBlocksInfo, and an error, if there is any. +func (c *iPBlocksInfos) Create(ctx context.Context, iPBlocksInfo *v1alpha1.IPBlocksInfo, opts v1.CreateOptions) (result *v1alpha1.IPBlocksInfo, err error) { + result = &v1alpha1.IPBlocksInfo{} + err = c.client.Post(). + Namespace(c.ns). + Resource("ipblocksinfos"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPBlocksInfo). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a iPBlocksInfo and updates it. Returns the server's representation of the iPBlocksInfo, and an error, if there is any. +func (c *iPBlocksInfos) Update(ctx context.Context, iPBlocksInfo *v1alpha1.IPBlocksInfo, opts v1.UpdateOptions) (result *v1alpha1.IPBlocksInfo, err error) { + result = &v1alpha1.IPBlocksInfo{} + err = c.client.Put(). + Namespace(c.ns). + Resource("ipblocksinfos"). + Name(iPBlocksInfo.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPBlocksInfo). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the iPBlocksInfo and deletes it. Returns an error if one occurs. +func (c *iPBlocksInfos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("ipblocksinfos"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *iPBlocksInfos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("ipblocksinfos"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched iPBlocksInfo. +func (c *iPBlocksInfos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPBlocksInfo, err error) { + result = &v1alpha1.IPBlocksInfo{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("ipblocksinfos"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/networkinfo.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/networkinfo.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/networkinfo.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/networkinfo.go index c26a78acf..2b4eff406 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/networkinfo.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/networkinfo.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -43,7 +43,7 @@ type networkInfos struct { } // newNetworkInfos returns a NetworkInfos -func newNetworkInfos(c *NsxV1alpha1Client, namespace string) *networkInfos { +func newNetworkInfos(c *CrdV1alpha1Client, namespace string) *networkInfos { return &networkInfos{ client: c.RESTClient(), ns: namespace, diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/securitypolicy.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/securitypolicy.go similarity index 97% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/securitypolicy.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/securitypolicy.go index a4414f02a..7db42e0d0 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/securitypolicy.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/securitypolicy.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -44,7 +44,7 @@ type securityPolicies struct { } // newSecurityPolicies returns a SecurityPolicies -func newSecurityPolicies(c *NsxV1alpha1Client, namespace string) *securityPolicies { +func newSecurityPolicies(c *CrdV1alpha1Client, namespace string) *securityPolicies { return &securityPolicies{ client: c.RESTClient(), ns: namespace, diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/staticroute.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/staticroute.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/staticroute.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/staticroute.go index 6c1b7f0f6..5047e953d 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/staticroute.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/staticroute.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -44,7 +44,7 @@ type staticRoutes struct { } // newStaticRoutes returns a StaticRoutes -func newStaticRoutes(c *NsxV1alpha1Client, namespace string) *staticRoutes { +func newStaticRoutes(c *CrdV1alpha1Client, namespace string) *staticRoutes { return &staticRoutes{ client: c.RESTClient(), ns: namespace, diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnet.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnet.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnet.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnet.go index c8fed4878..e1fa6b572 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnet.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnet.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -44,7 +44,7 @@ type subnets struct { } // newSubnets returns a Subnets -func newSubnets(c *NsxV1alpha1Client, namespace string) *subnets { +func newSubnets(c *CrdV1alpha1Client, namespace string) *subnets { return &subnets{ client: c.RESTClient(), ns: namespace, diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnetport.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnetport.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnetport.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnetport.go index b67c408f9..ce7458bcb 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnetport.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnetport.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -44,7 +44,7 @@ type subnetPorts struct { } // newSubnetPorts returns a SubnetPorts -func newSubnetPorts(c *NsxV1alpha1Client, namespace string) *subnetPorts { +func newSubnetPorts(c *CrdV1alpha1Client, namespace string) *subnetPorts { return &subnetPorts{ client: c.RESTClient(), ns: namespace, diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnetset.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnetset.go similarity index 96% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnetset.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnetset.go index b5bd0ee05..c135323f2 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/subnetset.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/subnetset.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -44,7 +44,7 @@ type subnetSets struct { } // newSubnetSets returns a SubnetSets -func newSubnetSets(c *NsxV1alpha1Client, namespace string) *subnetSets { +func newSubnetSets(c *CrdV1alpha1Client, namespace string) *subnetSets { return &subnetSets{ client: c.RESTClient(), ns: namespace, diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/vpc_client.go similarity index 54% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/vpc_client.go index 39cc72dc6..d7ba28a5f 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/vpc_client.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -8,74 +8,74 @@ package v1alpha1 import ( "net/http" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" ) -type NsxV1alpha1Interface interface { +type CrdV1alpha1Interface interface { RESTClient() rest.Interface - IPPoolsGetter - NSXServiceAccountsGetter + AddressBindingsGetter + IPAddressAllocationsGetter + IPBlocksInfosGetter NetworkInfosGetter SecurityPoliciesGetter StaticRoutesGetter SubnetsGetter SubnetPortsGetter SubnetSetsGetter - VPCsGetter VPCNetworkConfigurationsGetter } -// NsxV1alpha1Client is used to interact with features provided by the nsx.vmware.com group. -type NsxV1alpha1Client struct { +// CrdV1alpha1Client is used to interact with features provided by the crd.nsx.vmware.com group. +type CrdV1alpha1Client struct { restClient rest.Interface } -func (c *NsxV1alpha1Client) IPPools(namespace string) IPPoolInterface { - return newIPPools(c, namespace) +func (c *CrdV1alpha1Client) AddressBindings(namespace string) AddressBindingInterface { + return newAddressBindings(c, namespace) } -func (c *NsxV1alpha1Client) NSXServiceAccounts(namespace string) NSXServiceAccountInterface { - return newNSXServiceAccounts(c, namespace) +func (c *CrdV1alpha1Client) IPAddressAllocations(namespace string) IPAddressAllocationInterface { + return newIPAddressAllocations(c, namespace) } -func (c *NsxV1alpha1Client) NetworkInfos(namespace string) NetworkInfoInterface { +func (c *CrdV1alpha1Client) IPBlocksInfos(namespace string) IPBlocksInfoInterface { + return newIPBlocksInfos(c, namespace) +} + +func (c *CrdV1alpha1Client) NetworkInfos(namespace string) NetworkInfoInterface { return newNetworkInfos(c, namespace) } -func (c *NsxV1alpha1Client) SecurityPolicies(namespace string) SecurityPolicyInterface { +func (c *CrdV1alpha1Client) SecurityPolicies(namespace string) SecurityPolicyInterface { return newSecurityPolicies(c, namespace) } -func (c *NsxV1alpha1Client) StaticRoutes(namespace string) StaticRouteInterface { +func (c *CrdV1alpha1Client) StaticRoutes(namespace string) StaticRouteInterface { return newStaticRoutes(c, namespace) } -func (c *NsxV1alpha1Client) Subnets(namespace string) SubnetInterface { +func (c *CrdV1alpha1Client) Subnets(namespace string) SubnetInterface { return newSubnets(c, namespace) } -func (c *NsxV1alpha1Client) SubnetPorts(namespace string) SubnetPortInterface { +func (c *CrdV1alpha1Client) SubnetPorts(namespace string) SubnetPortInterface { return newSubnetPorts(c, namespace) } -func (c *NsxV1alpha1Client) SubnetSets(namespace string) SubnetSetInterface { +func (c *CrdV1alpha1Client) SubnetSets(namespace string) SubnetSetInterface { return newSubnetSets(c, namespace) } -func (c *NsxV1alpha1Client) VPCs(namespace string) VPCInterface { - return newVPCs(c, namespace) -} - -func (c *NsxV1alpha1Client) VPCNetworkConfigurations() VPCNetworkConfigurationInterface { +func (c *CrdV1alpha1Client) VPCNetworkConfigurations() VPCNetworkConfigurationInterface { return newVPCNetworkConfigurations(c) } -// NewForConfig creates a new NsxV1alpha1Client for the given config. +// NewForConfig creates a new CrdV1alpha1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*NsxV1alpha1Client, error) { +func NewForConfig(c *rest.Config) (*CrdV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err @@ -87,9 +87,9 @@ func NewForConfig(c *rest.Config) (*NsxV1alpha1Client, error) { return NewForConfigAndClient(&config, httpClient) } -// NewForConfigAndClient creates a new NsxV1alpha1Client for the given config and http client. +// NewForConfigAndClient creates a new CrdV1alpha1Client for the given config and http client. // Note the http client provided takes precedence over the configured transport values. -func NewForConfigAndClient(c *rest.Config, h *http.Client) (*NsxV1alpha1Client, error) { +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CrdV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err @@ -98,12 +98,12 @@ func NewForConfigAndClient(c *rest.Config, h *http.Client) (*NsxV1alpha1Client, if err != nil { return nil, err } - return &NsxV1alpha1Client{client}, nil + return &CrdV1alpha1Client{client}, nil } -// NewForConfigOrDie creates a new NsxV1alpha1Client for the given config and +// NewForConfigOrDie creates a new CrdV1alpha1Client for the given config and // panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *NsxV1alpha1Client { +func NewForConfigOrDie(c *rest.Config) *CrdV1alpha1Client { client, err := NewForConfig(c) if err != nil { panic(err) @@ -111,9 +111,9 @@ func NewForConfigOrDie(c *rest.Config) *NsxV1alpha1Client { return client } -// New creates a new NsxV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *NsxV1alpha1Client { - return &NsxV1alpha1Client{c} +// New creates a new CrdV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *CrdV1alpha1Client { + return &CrdV1alpha1Client{c} } func setConfigDefaults(config *rest.Config) error { @@ -131,7 +131,7 @@ func setConfigDefaults(config *rest.Config) error { // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. -func (c *NsxV1alpha1Client) RESTClient() rest.Interface { +func (c *CrdV1alpha1Client) RESTClient() rest.Interface { if c == nil { return nil } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/vpcnetworkconfiguration.go similarity index 97% rename from pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go rename to pkg/client/clientset/versioned/typed/vpc/v1alpha1/vpcnetworkconfiguration.go index af9db6d2a..f5f707cf6 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go +++ b/pkg/client/clientset/versioned/typed/vpc/v1alpha1/vpcnetworkconfiguration.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by client-gen. DO NOT EDIT. @@ -9,7 +9,7 @@ import ( "context" "time" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -43,7 +43,7 @@ type vPCNetworkConfigurations struct { } // newVPCNetworkConfigurations returns a VPCNetworkConfigurations -func newVPCNetworkConfigurations(c *NsxV1alpha1Client) *vPCNetworkConfigurations { +func newVPCNetworkConfigurations(c *CrdV1alpha1Client) *vPCNetworkConfigurations { return &vPCNetworkConfigurations{ client: c.RESTClient(), } diff --git a/pkg/client/go.mod b/pkg/client/go.mod index b78c2f36d..5982578d4 100644 --- a/pkg/client/go.mod +++ b/pkg/client/go.mod @@ -1,25 +1,24 @@ module github.com/vmware-tanzu/nsx-operator/pkg/client -go 1.21 +go 1.22.5 require ( - github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20231227030711-34390278f3cd - k8s.io/apimachinery v0.28.4 - k8s.io/client-go v0.28.4 + github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240813023528-cb525458c6ee + k8s.io/apimachinery v0.30.3 + k8s.io/client-go v0.30.3 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -29,23 +28,23 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.28.4 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + k8s.io/api v0.30.3 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/controller-runtime v0.14.5 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/pkg/client/go.sum b/pkg/client/go.sum index 32eecd8ef..a36e98be7 100644 --- a/pkg/client/go.sum +++ b/pkg/client/go.sum @@ -2,13 +2,12 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -20,14 +19,13 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -57,10 +55,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= -github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= +github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -76,10 +74,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20231227030711-34390278f3cd h1:rl/Yg5m2WrecTBHvf1ZSg/lMBOguIWOeaCf1uo5ARTQ= -github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20231227030711-34390278f3cd/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240813023528-cb525458c6ee h1:zbDYJ7kIfZRin5ifeezrLuiNhMezUqEaRtrEcrB5/4M= +github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240813023528-cb525458c6ee/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -92,43 +90,41 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -140,23 +136,23 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= -k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.14.5 h1:6xaWFqzT5KuAQ9ufgUaj1G/+C4Y1GRkhrxl+BJ9i+5s= sigs.k8s.io/controller-runtime v0.14.5/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 1499be5ad..4bf4d3bf6 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -12,7 +12,7 @@ import ( versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - nsxvmwarecom "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/nsx.vmware.com" + vpc "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/vpc" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -230,9 +230,9 @@ type SharedInformerFactory interface { // client. InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer - Nsx() nsxvmwarecom.Interface + Crd() vpc.Interface } -func (f *sharedInformerFactory) Nsx() nsxvmwarecom.Interface { - return nsxvmwarecom.New(f, f.namespace, f.tweakListOptions) +func (f *sharedInformerFactory) Crd() vpc.Interface { + return vpc.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 0c000e997..4cc4a7192 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -8,8 +8,7 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -40,31 +39,27 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=nsx.vmware.com, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("ippools"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().IPPools().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("nsxserviceaccounts"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().NSXServiceAccounts().Informer()}, nil + // Group=crd.nsx.vmware.com, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("addressbindings"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().AddressBindings().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("ipaddressallocations"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().IPAddressAllocations().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("ipblocksinfos"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().IPBlocksInfos().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("networkinfos"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().NetworkInfos().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().NetworkInfos().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("securitypolicies"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().SecurityPolicies().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().SecurityPolicies().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("staticroutes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().StaticRoutes().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().StaticRoutes().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("subnets"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().Subnets().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().Subnets().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("subnetports"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().SubnetPorts().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().SubnetPorts().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("subnetsets"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().SubnetSets().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("vpcs"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().VPCs().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().SubnetSets().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("vpcnetworkconfigurations"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().VPCNetworkConfigurations().Informer()}, nil - - // Group=nsx.vmware.com, Version=v1alpha2 - case v1alpha2.SchemeGroupVersion.WithResource("ippools"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha2().IPPools().Informer()}, nil + return &genericInformer{resource: resource.GroupResource(), informer: f.Crd().V1alpha1().VPCNetworkConfigurations().Informer()}, nil } diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go index 8ff8710c2..b0856fd71 100644 --- a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go +++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ippool.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ippool.go deleted file mode 100644 index 74f7f11cb..000000000 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ippool.go +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - time "time" - - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" - internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// IPPoolInformer provides access to a shared informer and lister for -// IPPools. -type IPPoolInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.IPPoolLister -} - -type iPPoolInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewIPPoolInformer constructs a new informer for IPPool type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewIPPoolInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredIPPoolInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredIPPoolInformer constructs a new informer for IPPool type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredIPPoolInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha1().IPPools(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha1().IPPools(namespace).Watch(context.TODO(), options) - }, - }, - &nsxvmwarecomv1alpha1.IPPool{}, - resyncPeriod, - indexers, - ) -} - -func (f *iPPoolInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredIPPoolInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *iPPoolInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.IPPool{}, f.defaultInformer) -} - -func (f *iPPoolInformer) Lister() v1alpha1.IPPoolLister { - return v1alpha1.NewIPPoolLister(f.Informer().GetIndexer()) -} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/nsxserviceaccount.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/nsxserviceaccount.go deleted file mode 100644 index 43fe4e489..000000000 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/nsxserviceaccount.go +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - time "time" - - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" - internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// NSXServiceAccountInformer provides access to a shared informer and lister for -// NSXServiceAccounts. -type NSXServiceAccountInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.NSXServiceAccountLister -} - -type nSXServiceAccountInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewNSXServiceAccountInformer constructs a new informer for NSXServiceAccount type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewNSXServiceAccountInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredNSXServiceAccountInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredNSXServiceAccountInformer constructs a new informer for NSXServiceAccount type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredNSXServiceAccountInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha1().NSXServiceAccounts(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha1().NSXServiceAccounts(namespace).Watch(context.TODO(), options) - }, - }, - &nsxvmwarecomv1alpha1.NSXServiceAccount{}, - resyncPeriod, - indexers, - ) -} - -func (f *nSXServiceAccountInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredNSXServiceAccountInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *nSXServiceAccountInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.NSXServiceAccount{}, f.defaultInformer) -} - -func (f *nSXServiceAccountInformer) Lister() v1alpha1.NSXServiceAccountLister { - return v1alpha1.NewNSXServiceAccountLister(f.Informer().GetIndexer()) -} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/vpc.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/vpc.go deleted file mode 100644 index 65643a0b7..000000000 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/vpc.go +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - time "time" - - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" - internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// VPCInformer provides access to a shared informer and lister for -// VPCs. -type VPCInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.VPCLister -} - -type vPCInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewVPCInformer constructs a new informer for VPC type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewVPCInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredVPCInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredVPCInformer constructs a new informer for VPC type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredVPCInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha1().VPCs(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha1().VPCs(namespace).Watch(context.TODO(), options) - }, - }, - &nsxvmwarecomv1alpha1.VPC{}, - resyncPeriod, - indexers, - ) -} - -func (f *vPCInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredVPCInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *vPCInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.VPC{}, f.defaultInformer) -} - -func (f *vPCInformer) Lister() v1alpha1.VPCLister { - return v1alpha1.NewVPCLister(f.Informer().GetIndexer()) -} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2/interface.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2/interface.go deleted file mode 100644 index 968cc1b77..000000000 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2/interface.go +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // IPPools returns a IPPoolInformer. - IPPools() IPPoolInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// IPPools returns a IPPoolInformer. -func (v *version) IPPools() IPPoolInformer { - return &iPPoolInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2/ippool.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2/ippool.go deleted file mode 100644 index 4000bff31..000000000 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2/ippool.go +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - "context" - time "time" - - nsxvmwarecomv1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" - versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" - internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha2" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// IPPoolInformer provides access to a shared informer and lister for -// IPPools. -type IPPoolInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha2.IPPoolLister -} - -type iPPoolInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewIPPoolInformer constructs a new informer for IPPool type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewIPPoolInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredIPPoolInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredIPPoolInformer constructs a new informer for IPPool type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredIPPoolInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha2().IPPools(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.NsxV1alpha2().IPPools(namespace).Watch(context.TODO(), options) - }, - }, - &nsxvmwarecomv1alpha2.IPPool{}, - resyncPeriod, - indexers, - ) -} - -func (f *iPPoolInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredIPPoolInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *iPPoolInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha2.IPPool{}, f.defaultInformer) -} - -func (f *iPPoolInformer) Lister() v1alpha2.IPPoolLister { - return v1alpha2.NewIPPoolLister(f.Informer().GetIndexer()) -} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/interface.go b/pkg/client/informers/externalversions/vpc/interface.go similarity index 68% rename from pkg/client/informers/externalversions/nsx.vmware.com/interface.go rename to pkg/client/informers/externalversions/vpc/interface.go index de4b44def..8bc643c31 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/interface.go +++ b/pkg/client/informers/externalversions/vpc/interface.go @@ -1,22 +1,19 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. -package nsx +package vpc import ( internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1" - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha2" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/vpc/v1alpha1" ) // Interface provides access to each of this group's versions. type Interface interface { // V1alpha1 provides access to shared informers for resources in V1alpha1. V1alpha1() v1alpha1.Interface - // V1alpha2 provides access to shared informers for resources in V1alpha2. - V1alpha2() v1alpha2.Interface } type group struct { @@ -34,8 +31,3 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1alpha1() v1alpha1.Interface { return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) } - -// V1alpha2 returns a new v1alpha2.Interface. -func (g *group) V1alpha2() v1alpha2.Interface { - return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/pkg/client/informers/externalversions/vpc/v1alpha1/addressbinding.go b/pkg/client/informers/externalversions/vpc/v1alpha1/addressbinding.go new file mode 100644 index 000000000..5b69842d6 --- /dev/null +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/addressbinding.go @@ -0,0 +1,77 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// AddressBindingInformer provides access to a shared informer and lister for +// AddressBindings. +type AddressBindingInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.AddressBindingLister +} + +type addressBindingInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewAddressBindingInformer constructs a new informer for AddressBinding type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewAddressBindingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredAddressBindingInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredAddressBindingInformer constructs a new informer for AddressBinding type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredAddressBindingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha1().AddressBindings(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha1().AddressBindings(namespace).Watch(context.TODO(), options) + }, + }, + &vpcv1alpha1.AddressBinding{}, + resyncPeriod, + indexers, + ) +} + +func (f *addressBindingInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredAddressBindingInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *addressBindingInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&vpcv1alpha1.AddressBinding{}, f.defaultInformer) +} + +func (f *addressBindingInformer) Lister() v1alpha1.AddressBindingLister { + return v1alpha1.NewAddressBindingLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go b/pkg/client/informers/externalversions/vpc/v1alpha1/interface.go similarity index 73% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/interface.go index a8b5b0ce9..296d61738 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/interface.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -11,10 +11,12 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { - // IPPools returns a IPPoolInformer. - IPPools() IPPoolInformer - // NSXServiceAccounts returns a NSXServiceAccountInformer. - NSXServiceAccounts() NSXServiceAccountInformer + // AddressBindings returns a AddressBindingInformer. + AddressBindings() AddressBindingInformer + // IPAddressAllocations returns a IPAddressAllocationInformer. + IPAddressAllocations() IPAddressAllocationInformer + // IPBlocksInfos returns a IPBlocksInfoInformer. + IPBlocksInfos() IPBlocksInfoInformer // NetworkInfos returns a NetworkInfoInformer. NetworkInfos() NetworkInfoInformer // SecurityPolicies returns a SecurityPolicyInformer. @@ -27,8 +29,6 @@ type Interface interface { SubnetPorts() SubnetPortInformer // SubnetSets returns a SubnetSetInformer. SubnetSets() SubnetSetInformer - // VPCs returns a VPCInformer. - VPCs() VPCInformer // VPCNetworkConfigurations returns a VPCNetworkConfigurationInformer. VPCNetworkConfigurations() VPCNetworkConfigurationInformer } @@ -44,14 +44,19 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } -// IPPools returns a IPPoolInformer. -func (v *version) IPPools() IPPoolInformer { - return &iPPoolInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +// AddressBindings returns a AddressBindingInformer. +func (v *version) AddressBindings() AddressBindingInformer { + return &addressBindingInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } -// NSXServiceAccounts returns a NSXServiceAccountInformer. -func (v *version) NSXServiceAccounts() NSXServiceAccountInformer { - return &nSXServiceAccountInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +// IPAddressAllocations returns a IPAddressAllocationInformer. +func (v *version) IPAddressAllocations() IPAddressAllocationInformer { + return &iPAddressAllocationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// IPBlocksInfos returns a IPBlocksInfoInformer. +func (v *version) IPBlocksInfos() IPBlocksInfoInformer { + return &iPBlocksInfoInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } // NetworkInfos returns a NetworkInfoInformer. @@ -84,11 +89,6 @@ func (v *version) SubnetSets() SubnetSetInformer { return &subnetSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } -// VPCs returns a VPCInformer. -func (v *version) VPCs() VPCInformer { - return &vPCInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - // VPCNetworkConfigurations returns a VPCNetworkConfigurationInformer. func (v *version) VPCNetworkConfigurations() VPCNetworkConfigurationInformer { return &vPCNetworkConfigurationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/vpc/v1alpha1/ipaddressallocation.go b/pkg/client/informers/externalversions/vpc/v1alpha1/ipaddressallocation.go new file mode 100644 index 000000000..6621cb674 --- /dev/null +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/ipaddressallocation.go @@ -0,0 +1,77 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// IPAddressAllocationInformer provides access to a shared informer and lister for +// IPAddressAllocations. +type IPAddressAllocationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.IPAddressAllocationLister +} + +type iPAddressAllocationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewIPAddressAllocationInformer constructs a new informer for IPAddressAllocation type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewIPAddressAllocationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredIPAddressAllocationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredIPAddressAllocationInformer constructs a new informer for IPAddressAllocation type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredIPAddressAllocationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha1().IPAddressAllocations(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha1().IPAddressAllocations(namespace).Watch(context.TODO(), options) + }, + }, + &vpcv1alpha1.IPAddressAllocation{}, + resyncPeriod, + indexers, + ) +} + +func (f *iPAddressAllocationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredIPAddressAllocationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *iPAddressAllocationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&vpcv1alpha1.IPAddressAllocation{}, f.defaultInformer) +} + +func (f *iPAddressAllocationInformer) Lister() v1alpha1.IPAddressAllocationLister { + return v1alpha1.NewIPAddressAllocationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/vpc/v1alpha1/ipblocksinfo.go b/pkg/client/informers/externalversions/vpc/v1alpha1/ipblocksinfo.go new file mode 100644 index 000000000..85e31e728 --- /dev/null +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/ipblocksinfo.go @@ -0,0 +1,77 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// IPBlocksInfoInformer provides access to a shared informer and lister for +// IPBlocksInfos. +type IPBlocksInfoInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.IPBlocksInfoLister +} + +type iPBlocksInfoInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewIPBlocksInfoInformer constructs a new informer for IPBlocksInfo type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewIPBlocksInfoInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredIPBlocksInfoInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredIPBlocksInfoInformer constructs a new informer for IPBlocksInfo type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredIPBlocksInfoInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha1().IPBlocksInfos(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CrdV1alpha1().IPBlocksInfos(namespace).Watch(context.TODO(), options) + }, + }, + &vpcv1alpha1.IPBlocksInfo{}, + resyncPeriod, + indexers, + ) +} + +func (f *iPBlocksInfoInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredIPBlocksInfoInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *iPBlocksInfoInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&vpcv1alpha1.IPBlocksInfo{}, f.defaultInformer) +} + +func (f *iPBlocksInfoInformer) Lister() v1alpha1.IPBlocksInfoLister { + return v1alpha1.NewIPBlocksInfoLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/networkinfo.go b/pkg/client/informers/externalversions/vpc/v1alpha1/networkinfo.go similarity index 86% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/networkinfo.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/networkinfo.go index dd0cad582..33444f66c 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/networkinfo.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/networkinfo.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -49,16 +49,16 @@ func NewFilteredNetworkInfoInformer(client versioned.Interface, namespace string if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().NetworkInfos(namespace).List(context.TODO(), options) + return client.CrdV1alpha1().NetworkInfos(namespace).List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().NetworkInfos(namespace).Watch(context.TODO(), options) + return client.CrdV1alpha1().NetworkInfos(namespace).Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.NetworkInfo{}, + &vpcv1alpha1.NetworkInfo{}, resyncPeriod, indexers, ) @@ -69,7 +69,7 @@ func (f *networkInfoInformer) defaultInformer(client versioned.Interface, resync } func (f *networkInfoInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.NetworkInfo{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.NetworkInfo{}, f.defaultInformer) } func (f *networkInfoInformer) Lister() v1alpha1.NetworkInfoLister { diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/securitypolicy.go b/pkg/client/informers/externalversions/vpc/v1alpha1/securitypolicy.go similarity index 87% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/securitypolicy.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/securitypolicy.go index e2c6d6496..1f057228d 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/securitypolicy.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/securitypolicy.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -49,16 +49,16 @@ func NewFilteredSecurityPolicyInformer(client versioned.Interface, namespace str if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().SecurityPolicies(namespace).List(context.TODO(), options) + return client.CrdV1alpha1().SecurityPolicies(namespace).List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().SecurityPolicies(namespace).Watch(context.TODO(), options) + return client.CrdV1alpha1().SecurityPolicies(namespace).Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.SecurityPolicy{}, + &vpcv1alpha1.SecurityPolicy{}, resyncPeriod, indexers, ) @@ -69,7 +69,7 @@ func (f *securityPolicyInformer) defaultInformer(client versioned.Interface, res } func (f *securityPolicyInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.SecurityPolicy{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.SecurityPolicy{}, f.defaultInformer) } func (f *securityPolicyInformer) Lister() v1alpha1.SecurityPolicyLister { diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/staticroute.go b/pkg/client/informers/externalversions/vpc/v1alpha1/staticroute.go similarity index 86% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/staticroute.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/staticroute.go index fc16b54c0..f904f45fa 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/staticroute.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/staticroute.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -49,16 +49,16 @@ func NewFilteredStaticRouteInformer(client versioned.Interface, namespace string if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().StaticRoutes(namespace).List(context.TODO(), options) + return client.CrdV1alpha1().StaticRoutes(namespace).List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().StaticRoutes(namespace).Watch(context.TODO(), options) + return client.CrdV1alpha1().StaticRoutes(namespace).Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.StaticRoute{}, + &vpcv1alpha1.StaticRoute{}, resyncPeriod, indexers, ) @@ -69,7 +69,7 @@ func (f *staticRouteInformer) defaultInformer(client versioned.Interface, resync } func (f *staticRouteInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.StaticRoute{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.StaticRoute{}, f.defaultInformer) } func (f *staticRouteInformer) Lister() v1alpha1.StaticRouteLister { diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnet.go b/pkg/client/informers/externalversions/vpc/v1alpha1/subnet.go similarity index 86% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnet.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/subnet.go index 133572393..a0f3f4ca4 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnet.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/subnet.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -49,16 +49,16 @@ func NewFilteredSubnetInformer(client versioned.Interface, namespace string, res if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().Subnets(namespace).List(context.TODO(), options) + return client.CrdV1alpha1().Subnets(namespace).List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().Subnets(namespace).Watch(context.TODO(), options) + return client.CrdV1alpha1().Subnets(namespace).Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.Subnet{}, + &vpcv1alpha1.Subnet{}, resyncPeriod, indexers, ) @@ -69,7 +69,7 @@ func (f *subnetInformer) defaultInformer(client versioned.Interface, resyncPerio } func (f *subnetInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.Subnet{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.Subnet{}, f.defaultInformer) } func (f *subnetInformer) Lister() v1alpha1.SubnetLister { diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnetport.go b/pkg/client/informers/externalversions/vpc/v1alpha1/subnetport.go similarity index 86% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnetport.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/subnetport.go index c681c3d6c..457cc3141 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnetport.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/subnetport.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -49,16 +49,16 @@ func NewFilteredSubnetPortInformer(client versioned.Interface, namespace string, if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().SubnetPorts(namespace).List(context.TODO(), options) + return client.CrdV1alpha1().SubnetPorts(namespace).List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().SubnetPorts(namespace).Watch(context.TODO(), options) + return client.CrdV1alpha1().SubnetPorts(namespace).Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.SubnetPort{}, + &vpcv1alpha1.SubnetPort{}, resyncPeriod, indexers, ) @@ -69,7 +69,7 @@ func (f *subnetPortInformer) defaultInformer(client versioned.Interface, resyncP } func (f *subnetPortInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.SubnetPort{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.SubnetPort{}, f.defaultInformer) } func (f *subnetPortInformer) Lister() v1alpha1.SubnetPortLister { diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnetset.go b/pkg/client/informers/externalversions/vpc/v1alpha1/subnetset.go similarity index 86% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnetset.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/subnetset.go index c94e8f931..847e8c792 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/subnetset.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/subnetset.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -49,16 +49,16 @@ func NewFilteredSubnetSetInformer(client versioned.Interface, namespace string, if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().SubnetSets(namespace).List(context.TODO(), options) + return client.CrdV1alpha1().SubnetSets(namespace).List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().SubnetSets(namespace).Watch(context.TODO(), options) + return client.CrdV1alpha1().SubnetSets(namespace).Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.SubnetSet{}, + &vpcv1alpha1.SubnetSet{}, resyncPeriod, indexers, ) @@ -69,7 +69,7 @@ func (f *subnetSetInformer) defaultInformer(client versioned.Interface, resyncPe } func (f *subnetSetInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.SubnetSet{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.SubnetSet{}, f.defaultInformer) } func (f *subnetSetInformer) Lister() v1alpha1.SubnetSetLister { diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go b/pkg/client/informers/externalversions/vpc/v1alpha1/vpcnetworkconfiguration.go similarity index 86% rename from pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go rename to pkg/client/informers/externalversions/vpc/v1alpha1/vpcnetworkconfiguration.go index 1354051cb..12b4ffb34 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go +++ b/pkg/client/informers/externalversions/vpc/v1alpha1/vpcnetworkconfiguration.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by informer-gen. DO NOT EDIT. @@ -9,10 +9,10 @@ import ( "context" time "time" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + vpcv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/vpc/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -48,16 +48,16 @@ func NewFilteredVPCNetworkConfigurationInformer(client versioned.Interface, resy if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().VPCNetworkConfigurations().List(context.TODO(), options) + return client.CrdV1alpha1().VPCNetworkConfigurations().List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.NsxV1alpha1().VPCNetworkConfigurations().Watch(context.TODO(), options) + return client.CrdV1alpha1().VPCNetworkConfigurations().Watch(context.TODO(), options) }, }, - &nsxvmwarecomv1alpha1.VPCNetworkConfiguration{}, + &vpcv1alpha1.VPCNetworkConfiguration{}, resyncPeriod, indexers, ) @@ -68,7 +68,7 @@ func (f *vPCNetworkConfigurationInformer) defaultInformer(client versioned.Inter } func (f *vPCNetworkConfigurationInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&nsxvmwarecomv1alpha1.VPCNetworkConfiguration{}, f.defaultInformer) + return f.factory.InformerFor(&vpcv1alpha1.VPCNetworkConfiguration{}, f.defaultInformer) } func (f *vPCNetworkConfigurationInformer) Lister() v1alpha1.VPCNetworkConfigurationLister { diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/ippool.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/ippool.go deleted file mode 100644 index 9feb6e5e3..000000000 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/ippool.go +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// IPPoolLister helps list IPPools. -// All objects returned here must be treated as read-only. -type IPPoolLister interface { - // List lists all IPPools in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.IPPool, err error) - // IPPools returns an object that can list and get IPPools. - IPPools(namespace string) IPPoolNamespaceLister - IPPoolListerExpansion -} - -// iPPoolLister implements the IPPoolLister interface. -type iPPoolLister struct { - indexer cache.Indexer -} - -// NewIPPoolLister returns a new IPPoolLister. -func NewIPPoolLister(indexer cache.Indexer) IPPoolLister { - return &iPPoolLister{indexer: indexer} -} - -// List lists all IPPools in the indexer. -func (s *iPPoolLister) List(selector labels.Selector) (ret []*v1alpha1.IPPool, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.IPPool)) - }) - return ret, err -} - -// IPPools returns an object that can list and get IPPools. -func (s *iPPoolLister) IPPools(namespace string) IPPoolNamespaceLister { - return iPPoolNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// IPPoolNamespaceLister helps list and get IPPools. -// All objects returned here must be treated as read-only. -type IPPoolNamespaceLister interface { - // List lists all IPPools in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.IPPool, err error) - // Get retrieves the IPPool from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.IPPool, error) - IPPoolNamespaceListerExpansion -} - -// iPPoolNamespaceLister implements the IPPoolNamespaceLister -// interface. -type iPPoolNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all IPPools in the indexer for a given namespace. -func (s iPPoolNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.IPPool, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.IPPool)) - }) - return ret, err -} - -// Get retrieves the IPPool from the indexer for a given namespace and name. -func (s iPPoolNamespaceLister) Get(name string) (*v1alpha1.IPPool, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("ippool"), name) - } - return obj.(*v1alpha1.IPPool), nil -} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/nsxserviceaccount.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/nsxserviceaccount.go deleted file mode 100644 index d84301511..000000000 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/nsxserviceaccount.go +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// NSXServiceAccountLister helps list NSXServiceAccounts. -// All objects returned here must be treated as read-only. -type NSXServiceAccountLister interface { - // List lists all NSXServiceAccounts in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.NSXServiceAccount, err error) - // NSXServiceAccounts returns an object that can list and get NSXServiceAccounts. - NSXServiceAccounts(namespace string) NSXServiceAccountNamespaceLister - NSXServiceAccountListerExpansion -} - -// nSXServiceAccountLister implements the NSXServiceAccountLister interface. -type nSXServiceAccountLister struct { - indexer cache.Indexer -} - -// NewNSXServiceAccountLister returns a new NSXServiceAccountLister. -func NewNSXServiceAccountLister(indexer cache.Indexer) NSXServiceAccountLister { - return &nSXServiceAccountLister{indexer: indexer} -} - -// List lists all NSXServiceAccounts in the indexer. -func (s *nSXServiceAccountLister) List(selector labels.Selector) (ret []*v1alpha1.NSXServiceAccount, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.NSXServiceAccount)) - }) - return ret, err -} - -// NSXServiceAccounts returns an object that can list and get NSXServiceAccounts. -func (s *nSXServiceAccountLister) NSXServiceAccounts(namespace string) NSXServiceAccountNamespaceLister { - return nSXServiceAccountNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// NSXServiceAccountNamespaceLister helps list and get NSXServiceAccounts. -// All objects returned here must be treated as read-only. -type NSXServiceAccountNamespaceLister interface { - // List lists all NSXServiceAccounts in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.NSXServiceAccount, err error) - // Get retrieves the NSXServiceAccount from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.NSXServiceAccount, error) - NSXServiceAccountNamespaceListerExpansion -} - -// nSXServiceAccountNamespaceLister implements the NSXServiceAccountNamespaceLister -// interface. -type nSXServiceAccountNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all NSXServiceAccounts in the indexer for a given namespace. -func (s nSXServiceAccountNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.NSXServiceAccount, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.NSXServiceAccount)) - }) - return ret, err -} - -// Get retrieves the NSXServiceAccount from the indexer for a given namespace and name. -func (s nSXServiceAccountNamespaceLister) Get(name string) (*v1alpha1.NSXServiceAccount, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("nsxserviceaccount"), name) - } - return obj.(*v1alpha1.NSXServiceAccount), nil -} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/vpc.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/vpc.go deleted file mode 100644 index a64fef879..000000000 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/vpc.go +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// VPCLister helps list VPCs. -// All objects returned here must be treated as read-only. -type VPCLister interface { - // List lists all VPCs in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.VPC, err error) - // VPCs returns an object that can list and get VPCs. - VPCs(namespace string) VPCNamespaceLister - VPCListerExpansion -} - -// vPCLister implements the VPCLister interface. -type vPCLister struct { - indexer cache.Indexer -} - -// NewVPCLister returns a new VPCLister. -func NewVPCLister(indexer cache.Indexer) VPCLister { - return &vPCLister{indexer: indexer} -} - -// List lists all VPCs in the indexer. -func (s *vPCLister) List(selector labels.Selector) (ret []*v1alpha1.VPC, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.VPC)) - }) - return ret, err -} - -// VPCs returns an object that can list and get VPCs. -func (s *vPCLister) VPCs(namespace string) VPCNamespaceLister { - return vPCNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// VPCNamespaceLister helps list and get VPCs. -// All objects returned here must be treated as read-only. -type VPCNamespaceLister interface { - // List lists all VPCs in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.VPC, err error) - // Get retrieves the VPC from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.VPC, error) - VPCNamespaceListerExpansion -} - -// vPCNamespaceLister implements the VPCNamespaceLister -// interface. -type vPCNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all VPCs in the indexer for a given namespace. -func (s vPCNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.VPC, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.VPC)) - }) - return ret, err -} - -// Get retrieves the VPC from the indexer for a given namespace and name. -func (s vPCNamespaceLister) Get(name string) (*v1alpha1.VPC, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("vpc"), name) - } - return obj.(*v1alpha1.VPC), nil -} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha2/expansion_generated.go b/pkg/client/listers/nsx.vmware.com/v1alpha2/expansion_generated.go deleted file mode 100644 index eeb66bfd9..000000000 --- a/pkg/client/listers/nsx.vmware.com/v1alpha2/expansion_generated.go +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha2 - -// IPPoolListerExpansion allows custom methods to be added to -// IPPoolLister. -type IPPoolListerExpansion interface{} - -// IPPoolNamespaceListerExpansion allows custom methods to be added to -// IPPoolNamespaceLister. -type IPPoolNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha2/ippool.go b/pkg/client/listers/nsx.vmware.com/v1alpha2/ippool.go deleted file mode 100644 index 434a3986f..000000000 --- a/pkg/client/listers/nsx.vmware.com/v1alpha2/ippool.go +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - v1alpha2 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha2" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// IPPoolLister helps list IPPools. -// All objects returned here must be treated as read-only. -type IPPoolLister interface { - // List lists all IPPools in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha2.IPPool, err error) - // IPPools returns an object that can list and get IPPools. - IPPools(namespace string) IPPoolNamespaceLister - IPPoolListerExpansion -} - -// iPPoolLister implements the IPPoolLister interface. -type iPPoolLister struct { - indexer cache.Indexer -} - -// NewIPPoolLister returns a new IPPoolLister. -func NewIPPoolLister(indexer cache.Indexer) IPPoolLister { - return &iPPoolLister{indexer: indexer} -} - -// List lists all IPPools in the indexer. -func (s *iPPoolLister) List(selector labels.Selector) (ret []*v1alpha2.IPPool, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha2.IPPool)) - }) - return ret, err -} - -// IPPools returns an object that can list and get IPPools. -func (s *iPPoolLister) IPPools(namespace string) IPPoolNamespaceLister { - return iPPoolNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// IPPoolNamespaceLister helps list and get IPPools. -// All objects returned here must be treated as read-only. -type IPPoolNamespaceLister interface { - // List lists all IPPools in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha2.IPPool, err error) - // Get retrieves the IPPool from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha2.IPPool, error) - IPPoolNamespaceListerExpansion -} - -// iPPoolNamespaceLister implements the IPPoolNamespaceLister -// interface. -type iPPoolNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all IPPools in the indexer for a given namespace. -func (s iPPoolNamespaceLister) List(selector labels.Selector) (ret []*v1alpha2.IPPool, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha2.IPPool)) - }) - return ret, err -} - -// Get retrieves the IPPool from the indexer for a given namespace and name. -func (s iPPoolNamespaceLister) Get(name string) (*v1alpha2.IPPool, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha2.Resource("ippool"), name) - } - return obj.(*v1alpha2.IPPool), nil -} diff --git a/pkg/client/listers/vpc/v1alpha1/addressbinding.go b/pkg/client/listers/vpc/v1alpha1/addressbinding.go new file mode 100644 index 000000000..3810c375e --- /dev/null +++ b/pkg/client/listers/vpc/v1alpha1/addressbinding.go @@ -0,0 +1,86 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// AddressBindingLister helps list AddressBindings. +// All objects returned here must be treated as read-only. +type AddressBindingLister interface { + // List lists all AddressBindings in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) + // AddressBindings returns an object that can list and get AddressBindings. + AddressBindings(namespace string) AddressBindingNamespaceLister + AddressBindingListerExpansion +} + +// addressBindingLister implements the AddressBindingLister interface. +type addressBindingLister struct { + indexer cache.Indexer +} + +// NewAddressBindingLister returns a new AddressBindingLister. +func NewAddressBindingLister(indexer cache.Indexer) AddressBindingLister { + return &addressBindingLister{indexer: indexer} +} + +// List lists all AddressBindings in the indexer. +func (s *addressBindingLister) List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.AddressBinding)) + }) + return ret, err +} + +// AddressBindings returns an object that can list and get AddressBindings. +func (s *addressBindingLister) AddressBindings(namespace string) AddressBindingNamespaceLister { + return addressBindingNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// AddressBindingNamespaceLister helps list and get AddressBindings. +// All objects returned here must be treated as read-only. +type AddressBindingNamespaceLister interface { + // List lists all AddressBindings in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) + // Get retrieves the AddressBinding from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.AddressBinding, error) + AddressBindingNamespaceListerExpansion +} + +// addressBindingNamespaceLister implements the AddressBindingNamespaceLister +// interface. +type addressBindingNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all AddressBindings in the indexer for a given namespace. +func (s addressBindingNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.AddressBinding)) + }) + return ret, err +} + +// Get retrieves the AddressBinding from the indexer for a given namespace and name. +func (s addressBindingNamespaceLister) Get(name string) (*v1alpha1.AddressBinding, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("addressbinding"), name) + } + return obj.(*v1alpha1.AddressBinding), nil +} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go b/pkg/client/listers/vpc/v1alpha1/expansion_generated.go similarity index 66% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go rename to pkg/client/listers/vpc/v1alpha1/expansion_generated.go index 1e24830fb..3b5ef6f01 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/vpc/v1alpha1/expansion_generated.go @@ -1,25 +1,33 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. package v1alpha1 -// IPPoolListerExpansion allows custom methods to be added to -// IPPoolLister. -type IPPoolListerExpansion interface{} +// AddressBindingListerExpansion allows custom methods to be added to +// AddressBindingLister. +type AddressBindingListerExpansion interface{} -// IPPoolNamespaceListerExpansion allows custom methods to be added to -// IPPoolNamespaceLister. -type IPPoolNamespaceListerExpansion interface{} +// AddressBindingNamespaceListerExpansion allows custom methods to be added to +// AddressBindingNamespaceLister. +type AddressBindingNamespaceListerExpansion interface{} -// NSXServiceAccountListerExpansion allows custom methods to be added to -// NSXServiceAccountLister. -type NSXServiceAccountListerExpansion interface{} +// IPAddressAllocationListerExpansion allows custom methods to be added to +// IPAddressAllocationLister. +type IPAddressAllocationListerExpansion interface{} -// NSXServiceAccountNamespaceListerExpansion allows custom methods to be added to -// NSXServiceAccountNamespaceLister. -type NSXServiceAccountNamespaceListerExpansion interface{} +// IPAddressAllocationNamespaceListerExpansion allows custom methods to be added to +// IPAddressAllocationNamespaceLister. +type IPAddressAllocationNamespaceListerExpansion interface{} + +// IPBlocksInfoListerExpansion allows custom methods to be added to +// IPBlocksInfoLister. +type IPBlocksInfoListerExpansion interface{} + +// IPBlocksInfoNamespaceListerExpansion allows custom methods to be added to +// IPBlocksInfoNamespaceLister. +type IPBlocksInfoNamespaceListerExpansion interface{} // NetworkInfoListerExpansion allows custom methods to be added to // NetworkInfoLister. @@ -69,14 +77,6 @@ type SubnetSetListerExpansion interface{} // SubnetSetNamespaceLister. type SubnetSetNamespaceListerExpansion interface{} -// VPCListerExpansion allows custom methods to be added to -// VPCLister. -type VPCListerExpansion interface{} - -// VPCNamespaceListerExpansion allows custom methods to be added to -// VPCNamespaceLister. -type VPCNamespaceListerExpansion interface{} - // VPCNetworkConfigurationListerExpansion allows custom methods to be added to // VPCNetworkConfigurationLister. type VPCNetworkConfigurationListerExpansion interface{} diff --git a/pkg/client/listers/vpc/v1alpha1/ipaddressallocation.go b/pkg/client/listers/vpc/v1alpha1/ipaddressallocation.go new file mode 100644 index 000000000..e5e708585 --- /dev/null +++ b/pkg/client/listers/vpc/v1alpha1/ipaddressallocation.go @@ -0,0 +1,86 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// IPAddressAllocationLister helps list IPAddressAllocations. +// All objects returned here must be treated as read-only. +type IPAddressAllocationLister interface { + // List lists all IPAddressAllocations in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) + // IPAddressAllocations returns an object that can list and get IPAddressAllocations. + IPAddressAllocations(namespace string) IPAddressAllocationNamespaceLister + IPAddressAllocationListerExpansion +} + +// iPAddressAllocationLister implements the IPAddressAllocationLister interface. +type iPAddressAllocationLister struct { + indexer cache.Indexer +} + +// NewIPAddressAllocationLister returns a new IPAddressAllocationLister. +func NewIPAddressAllocationLister(indexer cache.Indexer) IPAddressAllocationLister { + return &iPAddressAllocationLister{indexer: indexer} +} + +// List lists all IPAddressAllocations in the indexer. +func (s *iPAddressAllocationLister) List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.IPAddressAllocation)) + }) + return ret, err +} + +// IPAddressAllocations returns an object that can list and get IPAddressAllocations. +func (s *iPAddressAllocationLister) IPAddressAllocations(namespace string) IPAddressAllocationNamespaceLister { + return iPAddressAllocationNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// IPAddressAllocationNamespaceLister helps list and get IPAddressAllocations. +// All objects returned here must be treated as read-only. +type IPAddressAllocationNamespaceLister interface { + // List lists all IPAddressAllocations in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) + // Get retrieves the IPAddressAllocation from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.IPAddressAllocation, error) + IPAddressAllocationNamespaceListerExpansion +} + +// iPAddressAllocationNamespaceLister implements the IPAddressAllocationNamespaceLister +// interface. +type iPAddressAllocationNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all IPAddressAllocations in the indexer for a given namespace. +func (s iPAddressAllocationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.IPAddressAllocation)) + }) + return ret, err +} + +// Get retrieves the IPAddressAllocation from the indexer for a given namespace and name. +func (s iPAddressAllocationNamespaceLister) Get(name string) (*v1alpha1.IPAddressAllocation, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("ipaddressallocation"), name) + } + return obj.(*v1alpha1.IPAddressAllocation), nil +} diff --git a/pkg/client/listers/vpc/v1alpha1/ipblocksinfo.go b/pkg/client/listers/vpc/v1alpha1/ipblocksinfo.go new file mode 100644 index 000000000..ea1e283ac --- /dev/null +++ b/pkg/client/listers/vpc/v1alpha1/ipblocksinfo.go @@ -0,0 +1,86 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// IPBlocksInfoLister helps list IPBlocksInfos. +// All objects returned here must be treated as read-only. +type IPBlocksInfoLister interface { + // List lists all IPBlocksInfos in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.IPBlocksInfo, err error) + // IPBlocksInfos returns an object that can list and get IPBlocksInfos. + IPBlocksInfos(namespace string) IPBlocksInfoNamespaceLister + IPBlocksInfoListerExpansion +} + +// iPBlocksInfoLister implements the IPBlocksInfoLister interface. +type iPBlocksInfoLister struct { + indexer cache.Indexer +} + +// NewIPBlocksInfoLister returns a new IPBlocksInfoLister. +func NewIPBlocksInfoLister(indexer cache.Indexer) IPBlocksInfoLister { + return &iPBlocksInfoLister{indexer: indexer} +} + +// List lists all IPBlocksInfos in the indexer. +func (s *iPBlocksInfoLister) List(selector labels.Selector) (ret []*v1alpha1.IPBlocksInfo, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.IPBlocksInfo)) + }) + return ret, err +} + +// IPBlocksInfos returns an object that can list and get IPBlocksInfos. +func (s *iPBlocksInfoLister) IPBlocksInfos(namespace string) IPBlocksInfoNamespaceLister { + return iPBlocksInfoNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// IPBlocksInfoNamespaceLister helps list and get IPBlocksInfos. +// All objects returned here must be treated as read-only. +type IPBlocksInfoNamespaceLister interface { + // List lists all IPBlocksInfos in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.IPBlocksInfo, err error) + // Get retrieves the IPBlocksInfo from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.IPBlocksInfo, error) + IPBlocksInfoNamespaceListerExpansion +} + +// iPBlocksInfoNamespaceLister implements the IPBlocksInfoNamespaceLister +// interface. +type iPBlocksInfoNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all IPBlocksInfos in the indexer for a given namespace. +func (s iPBlocksInfoNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.IPBlocksInfo, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.IPBlocksInfo)) + }) + return ret, err +} + +// Get retrieves the IPBlocksInfo from the indexer for a given namespace and name. +func (s iPBlocksInfoNamespaceLister) Get(name string) (*v1alpha1.IPBlocksInfo, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("ipblocksinfo"), name) + } + return obj.(*v1alpha1.IPBlocksInfo), nil +} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/networkinfo.go b/pkg/client/listers/vpc/v1alpha1/networkinfo.go similarity index 95% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/networkinfo.go rename to pkg/client/listers/vpc/v1alpha1/networkinfo.go index b42682721..af90f6cae 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/networkinfo.go +++ b/pkg/client/listers/vpc/v1alpha1/networkinfo.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/securitypolicy.go b/pkg/client/listers/vpc/v1alpha1/securitypolicy.go similarity index 95% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/securitypolicy.go rename to pkg/client/listers/vpc/v1alpha1/securitypolicy.go index d5b0b0ca8..90dad634e 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/securitypolicy.go +++ b/pkg/client/listers/vpc/v1alpha1/securitypolicy.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/staticroute.go b/pkg/client/listers/vpc/v1alpha1/staticroute.go similarity index 95% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/staticroute.go rename to pkg/client/listers/vpc/v1alpha1/staticroute.go index 3f060010c..a607e815e 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/staticroute.go +++ b/pkg/client/listers/vpc/v1alpha1/staticroute.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/subnet.go b/pkg/client/listers/vpc/v1alpha1/subnet.go similarity index 95% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/subnet.go rename to pkg/client/listers/vpc/v1alpha1/subnet.go index 0b8cd736b..ef18873a2 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/subnet.go +++ b/pkg/client/listers/vpc/v1alpha1/subnet.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/subnetport.go b/pkg/client/listers/vpc/v1alpha1/subnetport.go similarity index 95% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/subnetport.go rename to pkg/client/listers/vpc/v1alpha1/subnetport.go index 7f1b170aa..db1c47ba9 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/subnetport.go +++ b/pkg/client/listers/vpc/v1alpha1/subnetport.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/subnetset.go b/pkg/client/listers/vpc/v1alpha1/subnetset.go similarity index 95% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/subnetset.go rename to pkg/client/listers/vpc/v1alpha1/subnetset.go index 9898f6097..72cb995e6 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/subnetset.go +++ b/pkg/client/listers/vpc/v1alpha1/subnetset.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go b/pkg/client/listers/vpc/v1alpha1/vpcnetworkconfiguration.go similarity index 93% rename from pkg/client/listers/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go rename to pkg/client/listers/vpc/v1alpha1/vpcnetworkconfiguration.go index 5fe6b4c05..e85374e52 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration.go +++ b/pkg/client/listers/vpc/v1alpha1/vpcnetworkconfiguration.go @@ -1,4 +1,4 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. +/* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ // Code generated by lister-gen. DO NOT EDIT. @@ -6,7 +6,7 @@ package v1alpha1 import ( - v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" diff --git a/pkg/config/config.go b/pkg/config/config.go index dfac3a4a2..83adb519f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -11,6 +11,7 @@ import ( "fmt" "os" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "go.uber.org/zap" ini "gopkg.in/ini.v1" @@ -25,16 +26,15 @@ const ( // LicenseInterval is the timeout for checking license status LicenseInterval = 86400 // LicenseIntervalForDFW is the timeout for checking license status while no DFW license enabled - LicenseIntervalForDFW = 1800 - defaultWebhookPort = 9981 - defaultWebhookCertPath = "/tmp/k8s-webhook-server/serving-certs" + LicenseIntervalForDFW = 1800 + defaultWebhookPort = 9981 + WebhookCertDir = "/tmp/k8s-webhook-server/serving-certs" ) var ( LogLevel int ProbeAddr, MetricsAddr string WebhookServerPort int - WebhookCertDir string configFilePath = "" configLog *zap.SugaredLogger tokenProvider auth.TokenProvider @@ -112,12 +112,15 @@ type NsxConfig struct { SingleTierSrTopology bool `ini:"single_tier_sr_topology"` EnforcementPoint string `ini:"enforcement_point"` DefaultProject string `ini:"default_project"` - ExternalIPv4Blocks []string `ini:"external_ipv4_blocks"` DefaultSubnetSize int `ini:"default_subnet_size"` DefaultTimeout int `ini:"default_timeout"` EnvoyHost string `ini:"envoy_host"` EnvoyPort int `ini:"envoy_port"` LicenseValidationInterval int `ini:"license_validation_interval"` + UseAVILoadBalancer bool `ini:"use_avi_lb"` + UseNSXLoadBalancer *bool `ini:"use_native_loadbalancer"` + RelaxNSXLBScaleValication bool `ini:"relax_scale_validation"` + NSXLBSize string `ini:"service_size"` } type K8sConfig struct { @@ -158,7 +161,6 @@ func AddFlags() { flag.StringVar(&MetricsAddr, "metrics-bind-address", ":8093", "The address the metrics endpoint binds to.") flag.IntVar(&LogLevel, "log-level", 0, "Use zap-core log system.") flag.IntVar(&WebhookServerPort, "webhook-server-port", defaultWebhookPort, "Port number to expose the controller webhook server") - flag.StringVar(&WebhookCertDir, "webhook-cert-dir", defaultWebhookCertPath, "Directory for certificate for webhook server") flag.Parse() } @@ -408,3 +410,11 @@ func (coeConfig *CoeConfig) validate() error { func (nsxConfig *NsxConfig) ValidateConfigFromCmd() error { return nsxConfig.validate(true) } + +func (nsxConfig *NsxConfig) GetNSXLBSize() string { + lbsSize := nsxConfig.NSXLBSize + if lbsSize == "" { + lbsSize = model.LBService_SIZE_SMALL + } + return lbsSize +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 6ca245042..bd59e2741 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" ) func TestConfig_VCConfig(t *testing.T) { @@ -176,3 +177,35 @@ func TestNSXOperatorConfig_GetCACert(t *testing.T) { }) } } + +func TestNsxConfig_GetServiceSize(t *testing.T) { + type fields struct { + ServiceSize string + } + tests := []struct { + name string + fields fields + want string + }{{ + name: "default", + fields: fields{ + ServiceSize: "", + }, + want: model.LBService_SIZE_SMALL, + }, { + name: "large", + fields: fields{ + ServiceSize: model.LBService_SIZE_LARGE, + }, + want: model.LBService_SIZE_LARGE, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nsxConfig := &NsxConfig{ + NSXLBSize: tt.fields.ServiceSize, + } + assert.Equalf(t, tt.want, nsxConfig.GetNSXLBSize(), "GetNSXLBSize()") + }) + } +} diff --git a/pkg/controllers/common/types.go b/pkg/controllers/common/types.go index 90c04918b..4003ed1bb 100644 --- a/pkg/controllers/common/types.go +++ b/pkg/controllers/common/types.go @@ -1,26 +1,28 @@ package common import ( + "context" "time" ctrl "sigs.k8s.io/controller-runtime" ) const ( - MetricResTypeSecurityPolicy = "securitypolicy" - MetricResTypeNetworkPolicy = "networkpolicy" - MetricResTypeIPPool = "ippool" - MetricResTypeNSXServiceAccount = "nsxserviceaccount" - MetricResTypeSubnetPort = "subnetport" - MetricResTypeStaticRoute = "staticroute" - MetricResTypeSubnet = "subnet" - MetricResTypeSubnetSet = "subnetset" - MetricResTypeVPC = "vpc" - MetricResTypeNamespace = "namespace" - MetricResTypePod = "pod" - MetricResTypeNode = "node" - MetricResTypeServiceLb = "servicelb" - MaxConcurrentReconciles = 8 + MetricResTypeSecurityPolicy = "securitypolicy" + MetricResTypeNetworkPolicy = "networkpolicy" + MetricResTypeIPPool = "ippool" + MetricResTypeIPAddressAllocation = "ipaddressallocation" + MetricResTypeNSXServiceAccount = "nsxserviceaccount" + MetricResTypeSubnetPort = "subnetport" + MetricResTypeStaticRoute = "staticroute" + MetricResTypeSubnet = "subnet" + MetricResTypeSubnetSet = "subnetset" + MetricResTypeNetworkInfo = "networkinfo" + MetricResTypeNamespace = "namespace" + MetricResTypePod = "pod" + MetricResTypeNode = "node" + MetricResTypeServiceLb = "servicelb" + MaxConcurrentReconciles = 8 LabelK8sMasterRole = "node-role.kubernetes.io/master" LabelK8sControlRole = "node-role.kubernetes.io/control-plane" @@ -31,6 +33,7 @@ var ( ResultRequeue = ctrl.Result{Requeue: true} // for k8s events that need to retry in short loop, eg: namespace creation ResultRequeueAfter10sec = ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second} + ResultRequeueAfter60sec = ctrl.Result{Requeue: true, RequeueAfter: 60 * time.Second} // for unstable event, eg: failed to k8s resources when reconciling, may due to k8s unstable ResultRequeueAfter5mins = ctrl.Result{Requeue: true, RequeueAfter: 5 * time.Minute} ) @@ -41,3 +44,8 @@ const ( ReasonFailDelete = "FailDelete" ReasonFailUpdate = "FailUpdate" ) + +// GarbageCollector interface with collectGarbage method +type GarbageCollector interface { + CollectGarbage(ctx context.Context) +} diff --git a/pkg/controllers/common/utils.go b/pkg/controllers/common/utils.go index f837dd9c2..018e5e30e 100644 --- a/pkg/controllers/common/utils.go +++ b/pkg/controllers/common/utils.go @@ -6,20 +6,21 @@ import ( "fmt" "strings" "sync" + "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" k8sclient "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) var ( - log = logger.Log + log = &logger.Log lock = &sync.Mutex{} ) @@ -53,29 +54,23 @@ func AllocateSubnetFromSubnetSet(subnetSet *v1alpha1.SubnetSet, vpcService servi return subnetService.CreateOrUpdateSubnet(subnetSet, vpcInfoList[0], tags) } -func getSharedNamespaceAndVpcForNamespace(client k8sclient.Client, ctx context.Context, namespaceName string) (string, string, error) { +func getSharedNamespaceForNamespace(client k8sclient.Client, ctx context.Context, namespaceName string) (string, error) { namespace := &v1.Namespace{} namespacedName := types.NamespacedName{Name: namespaceName} if err := client.Get(ctx, namespacedName, namespace); err != nil { log.Error(err, "failed to get target namespace during getting VPC for namespace") - return "", "", err + return "", err } - vpcAnnotation, exists := namespace.Annotations[servicecommon.AnnotationVPCName] + sharedNamespaceName, exists := namespace.Annotations[servicecommon.AnnotationSharedVPCNamespace] if !exists { - return "", "", nil - } - array := strings.Split(vpcAnnotation, "/") - if len(array) != 2 { - err := fmt.Errorf("invalid annotation value of '%s': %s", servicecommon.AnnotationVPCName, vpcAnnotation) - return "", "", err + return "", nil } - sharedNamespaceName, sharedVpcName := array[0], array[1] - log.Info("got shared VPC for namespace", "current namespace", namespaceName, "shared VPC", sharedVpcName, "shared namespace", sharedNamespaceName) - return sharedNamespaceName, sharedVpcName, nil + log.Info("got shared VPC namespace", "current namespace", namespaceName, "shared namespace", sharedNamespaceName) + return sharedNamespaceName, nil } func GetDefaultSubnetSet(client k8sclient.Client, ctx context.Context, namespace string, resourceType string) (*v1alpha1.SubnetSet, error) { - targetNamespace, _, err := getSharedNamespaceAndVpcForNamespace(client, ctx, namespace) + targetNamespace, err := getSharedNamespaceForNamespace(client, ctx, namespace) if err != nil { return nil, err } @@ -126,24 +121,39 @@ func NodeIsMaster(node *v1.Node) bool { return false } -func GetVirtualMachineNameForSubnetPort(subnetPort *v1alpha1.SubnetPort) (string, error) { +func GetVirtualMachineNameForSubnetPort(subnetPort *v1alpha1.SubnetPort) (string, string, error) { annotations := subnetPort.GetAnnotations() if annotations == nil { - return "", nil + return "", "", nil } attachmentRef, exist := annotations[servicecommon.AnnotationAttachmentRef] if !exist { - return "", nil + return "", "", nil } array := strings.Split(attachmentRef, "/") - if len(array) != 2 || !strings.EqualFold(array[0], servicecommon.ResourceTypeVirtualMachine) { + if len(array) != 3 || !strings.EqualFold(array[0], servicecommon.ResourceTypeVirtualMachine) { err := fmt.Errorf("invalid annotation value of '%s': %s", servicecommon.AnnotationAttachmentRef, attachmentRef) - return "", err + return "", "", err } - return array[1], nil + return array[1], array[2], nil } // NumReconcile now uses the fix number of concurrency func NumReconcile() int { return MaxConcurrentReconciles } + +func GenericGarbageCollector(cancel chan bool, timeout time.Duration, f func(ctx context.Context)) { + ctx := context.Background() + ticker := time.NewTicker(timeout) + defer ticker.Stop() + + for { + select { + case <-cancel: + return + case <-ticker.C: + f(ctx) + } + } +} diff --git a/pkg/controllers/common/utils_test.go b/pkg/controllers/common/utils_test.go index a2b19fca0..f9e6209b6 100644 --- a/pkg/controllers/common/utils_test.go +++ b/pkg/controllers/common/utils_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" ) func TestGetVirtualMachineNameForSubnetPort(t *testing.T) { @@ -15,8 +15,9 @@ func TestGetVirtualMachineNameForSubnetPort(t *testing.T) { subnetPort *v1alpha1.SubnetPort } type want struct { - vm string - err error + vm string + port string + err error } tests := []struct { name string @@ -28,15 +29,15 @@ func TestGetVirtualMachineNameForSubnetPort(t *testing.T) { args{&v1alpha1.SubnetPort{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - "nsx.vmware.com/attachment_ref": "virtualmachine/abc", + "nsx.vmware.com/attachment_ref": "virtualmachine/abc/port1", }, }}}, - want{vm: "abc", err: nil}, + want{vm: "abc", port: "port1", err: nil}, }, { "port_without_annotation", args{&v1alpha1.SubnetPort{}}, - want{vm: "", err: nil}, + want{vm: "", port: "", err: nil}, }, { "port_with_invalid_annotation", @@ -46,14 +47,17 @@ func TestGetVirtualMachineNameForSubnetPort(t *testing.T) { "nsx.vmware.com/attachment_ref": "invalid/abc", }, }}}, - want{vm: "", err: fmt.Errorf("invalid annotation value of 'nsx.vmware.com/attachment_ref': invalid/abc")}, + want{vm: "", port: "", err: fmt.Errorf("invalid annotation value of 'nsx.vmware.com/attachment_ref': invalid/abc")}, }, } for _, tt := range tests { - got, err := GetVirtualMachineNameForSubnetPort(tt.args.subnetPort) + got1, got2, err := GetVirtualMachineNameForSubnetPort(tt.args.subnetPort) assert.Equal(t, err, tt.want.err) - if got != tt.want.vm { - t.Errorf("%s failed: got %s, want %s", tt.name, got, tt.want.vm) + if got1 != tt.want.vm { + t.Errorf("%s failed: got %s, want %s", tt.name, got1, tt.want.vm) + } + if got2 != tt.want.port { + t.Errorf("%s failed: got %s, want %s", tt.name, got2, tt.want.port) } } } diff --git a/pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go new file mode 100644 index 000000000..a9c0a5a73 --- /dev/null +++ b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go @@ -0,0 +1,214 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package ipaddressallocation + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apimachineryruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" + "github.com/vmware-tanzu/nsx-operator/pkg/logger" + "github.com/vmware-tanzu/nsx-operator/pkg/metrics" + servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" +) + +var ( + log = logger.Log + resultNormal = common.ResultNormal + resultRequeue = common.ResultRequeue + MetricResType = common.MetricResTypeIPAddressAllocation +) + +// IPAddressAllocationReconciler reconciles a IPAddressAllocation object +type IPAddressAllocationReconciler struct { + client.Client + Scheme *apimachineryruntime.Scheme + Service *ipaddressallocation.IPAddressAllocationService + VPCService servicecommon.VPCServiceProvider + Recorder record.EventRecorder +} + +func deleteSuccess(r *IPAddressAllocationReconciler, _ context.Context, o *v1alpha1.IPAddressAllocation) { + r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "IPAddressAllocation CR has been successfully deleted") + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) +} + +func deleteFail(r *IPAddressAllocationReconciler, c context.Context, o *v1alpha1.IPAddressAllocation, e *error) { + r.setReadyStatusFalse(c, o, metav1.Now(), e) + r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) +} + +func updateSuccess(r *IPAddressAllocationReconciler, c context.Context, o *v1alpha1.IPAddressAllocation) { + r.setReadyStatusTrue(c, o, metav1.Now()) + r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "IPAddressAllocation CR has been successfully updated") + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) +} + +func updateFail(r *IPAddressAllocationReconciler, c context.Context, o *v1alpha1.IPAddressAllocation, e *error) { + r.setReadyStatusFalse(c, o, metav1.Now(), e) + r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) +} + +func (r *IPAddressAllocationReconciler) setReadyStatusFalse(ctx context.Context, ipaddressallocation *v1alpha1.IPAddressAllocation, transitionTime metav1.Time, err *error) { + conditions := []v1alpha1.Condition{ + { + Type: v1alpha1.Ready, + Status: v1.ConditionFalse, + Message: "NSX IPAddressAllocation could not be created or updated", + Reason: fmt.Sprintf( + "error occurred while processing the IPAddressAllocation CR. Error: %v", + *err, + ), + LastTransitionTime: transitionTime, + }, + } + ipaddressallocation.Status.Conditions = conditions + e := r.Client.Status().Update(ctx, ipaddressallocation) + if e != nil { + log.Error(e, "unable to update IPAddressAllocation status", "IPAddressAllocation", ipaddressallocation) + } +} + +func (r *IPAddressAllocationReconciler) setReadyStatusTrue(ctx context.Context, ipaddressallocation *v1alpha1.IPAddressAllocation, transitionTime metav1.Time) { + conditions := []v1alpha1.Condition{ + { + Type: v1alpha1.Ready, + Status: v1.ConditionTrue, + Message: "NSX IPAddressAllocation has been successfully created/updated", + Reason: "", + LastTransitionTime: transitionTime, + }, + } + ipaddressallocation.Status.Conditions = conditions + e := r.Client.Status().Update(ctx, ipaddressallocation) + if e != nil { + log.Error(e, "unable to update IPAddressAllocation status", "IPAddressAllocation", ipaddressallocation) + } +} + +func (r *IPAddressAllocationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := &v1alpha1.IPAddressAllocation{} + log.Info("reconciling IPAddressAllocation CR", "IPAddressAllocation", req.NamespacedName) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + log.Error(err, "unable to fetch IPAddressAllocation CR", "req", req.NamespacedName) + return resultNormal, client.IgnoreNotFound(err) + } + if obj.ObjectMeta.DeletionTimestamp.IsZero() { + return r.handleUpdate(ctx, req, obj) + } + return r.handleDeletion(ctx, req, obj) +} + +func (r *IPAddressAllocationReconciler) handleUpdate(ctx context.Context, req ctrl.Request, obj *v1alpha1.IPAddressAllocation) (ctrl.Result, error) { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType) + if !controllerutil.ContainsFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) { + controllerutil.AddFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) + if err := r.Client.Update(ctx, obj); err != nil { + log.Error(err, "add finalizer", "IPAddressAllocation", req.NamespacedName) + updateFail(r, ctx, obj, &err) + return resultRequeue, err + } + log.V(1).Info("added finalizer on IPAddressAllocation CR", "IPAddressAllocation", req.NamespacedName) + } + + updated, err := r.Service.CreateOrUpdateIPAddressAllocation(obj) + if err != nil { + updateFail(r, ctx, obj, &err) + return resultRequeue, err + } + if updated { + updateSuccess(r, ctx, obj) + } + return resultNormal, nil +} + +func (r *IPAddressAllocationReconciler) handleDeletion(ctx context.Context, req ctrl.Request, obj *v1alpha1.IPAddressAllocation) (ctrl.Result, error) { + if controllerutil.ContainsFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) + if err := r.Service.DeleteIPAddressAllocation(obj); err != nil { + log.Error(err, "deletion failed, would retry exponentially", "IPAddressAllocation", req.NamespacedName) + deleteFail(r, ctx, obj, &err) + return resultRequeue, err + } + controllerutil.RemoveFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) + if err := r.Client.Update(ctx, obj); err != nil { + log.Error(err, "deletion failed, would retry exponentially", "IPAddressAllocation", req.NamespacedName) + deleteFail(r, ctx, obj, &err) + return resultRequeue, err + } + log.V(1).Info("removed finalizer on IPAddressAllocation CR", "IPAddressAllocation", req.NamespacedName) + deleteSuccess(r, ctx, obj) + log.Info("successfully deleted IPAddressAllocation CR and all subnets", "IPAddressAllocation", obj) + } else { + // only print a message because it's not a normal case + log.Info("IPAddressAllocation CR is being deleted but its finalizers cannot be recognized", "IPAddressAllocation", req.NamespacedName) + } + return resultNormal, nil +} + +func (r *IPAddressAllocationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.IPAddressAllocation{}). + WithEventFilter(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + // Ignore updates to CR status in which case metadata.Generation does not change + return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration() + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // Suppress Delete events to avoid filtering them out in the Reconcile function + return false + }, + }). + WithOptions( + controller.Options{ + MaxConcurrentReconciles: common.NumReconcile(), + }). + Complete(r) +} + +func (r *IPAddressAllocationReconciler) CollectGarbage(ctx context.Context) { + log.Info("IPAddressAllocation garbage collector started") + ipAddressAllocationSet := r.Service.ListIPAddressAllocationID() + if len(ipAddressAllocationSet) == 0 { + return + } + + ipAddressAllocationList := &v1alpha1.IPAddressAllocationList{} + if err := r.Client.List(ctx, ipAddressAllocationList); err != nil { + log.Error(err, "failed to list IPAddressAllocation CR") + return + } + CRIPAddressAllocationSet := sets.New[string]() + for _, ipa := range ipAddressAllocationList.Items { + CRIPAddressAllocationSet.Insert(string(ipa.UID)) + } + + log.V(2).Info("IPAddressAllocation garbage collector", "nsxIPAddressAllocationSet", ipAddressAllocationSet, "CRIPAddressAllocationSet", CRIPAddressAllocationSet) + + diffSet := ipAddressAllocationSet.Difference(CRIPAddressAllocationSet) + for elem := range diffSet { + log.Info("GC collected nsx IPAddressAllocation", "UID", elem) + if err := r.Service.DeleteIPAddressAllocation(types.UID(elem)); err != nil { + log.Error(err, "failed to delete nsx IPAddressAllocation", "UID", elem) + } + } +} diff --git a/pkg/controllers/ippool/ippool_controller_test.go b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go similarity index 64% rename from pkg/controllers/ippool/ippool_controller_test.go rename to pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go index e179adfef..2eee4de45 100644 --- a/pkg/controllers/ippool/ippool_controller_test.go +++ b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go @@ -1,14 +1,14 @@ /* Copyright © 2021 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package ippool +package ipaddressallocation import ( "context" "errors" "reflect" + "sync" "testing" - "time" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -18,33 +18,31 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" - controllerruntime "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" _ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ippool" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" ) -func NewFakeIPPoolReconciler() *IPPoolReconciler { - return &IPPoolReconciler{ +func NewFakeIPAddressAllocationReconciler() *IPAddressAllocationReconciler { + return &IPAddressAllocationReconciler{ Client: fake.NewClientBuilder().Build(), Scheme: fake.NewClientBuilder().Build().Scheme(), Service: nil, } } -func TestIPPoolController_setReadyStatusTrue(t *testing.T) { - r := NewFakeIPPoolReconciler() +func TestIPAddressAllocationController_setReadyStatusTrue(t *testing.T) { + r := NewFakeIPAddressAllocationReconciler() ctx := context.TODO() - dummyIPPool := &v1alpha2.IPPool{} + dummyIPAddressAllocation := &v1alpha1.IPAddressAllocation{} transitionTime := metav1.Now() // Case: Static Route CRD creation fails @@ -52,14 +50,14 @@ func TestIPPoolController_setReadyStatusTrue(t *testing.T) { { Type: v1alpha1.Ready, Status: v1.ConditionTrue, - Message: "NSX IPPool has been successfully created/updated", + Message: "NSX IPAddressAllocation has been successfully created/updated", Reason: "", LastTransitionTime: transitionTime, }, } - r.setReadyStatusTrue(&ctx, dummyIPPool, transitionTime) + r.setReadyStatusTrue(ctx, dummyIPAddressAllocation, transitionTime) - if !reflect.DeepEqual(dummyIPPool.Status.Conditions, newConditions) { + if !reflect.DeepEqual(dummyIPAddressAllocation.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") } } @@ -87,12 +85,12 @@ func (recorder fakeRecorder) Eventf(object runtime.Object, eventtype, reason, me func (recorder fakeRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { } -func TestIPPoolReconciler_Reconcile(t *testing.T) { +func TestIPAddressAllocationReconciler_Reconcile(t *testing.T) { mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) - service := &ippool.IPPoolService{ + service := &ipaddressallocation.IPAddressAllocationService{ Service: common.Service{ NSXClient: &nsx.Client{}, @@ -105,14 +103,19 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { } service.NSXConfig.CoeConfig = &config.CoeConfig{} service.NSXConfig.Cluster = "k8s_cluster" - r := &IPPoolReconciler{ + r := &IPAddressAllocationReconciler{ Client: k8sClient, Scheme: nil, Service: service, Recorder: fakeRecorder{}, } ctx := context.Background() - req := controllerruntime.Request{NamespacedName: types.NamespacedName{Namespace: "dummy", Name: "dummy"}} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "dummy", Name: "dummy"}} + + // common.GcOnce do nothing + var once sync.Once + pat := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) + defer pat.Reset() // not found errNotFound := errors.New("not found") @@ -121,10 +124,8 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { assert.Equal(t, err, errNotFound) // DeletionTimestamp.IsZero = ture, client update failed - sp := &v1alpha2.IPPool{} + sp := &v1alpha1.IPAddressAllocation{} k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { - v1sp := obj.(*v1alpha2.IPPool) - v1sp.Spec.Type = "Public" return nil }) err = errors.New("Update failed") @@ -136,14 +137,14 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { // DeletionTimestamp.IsZero = false, Finalizers doesn't include util.FinalizerName k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { - v1sp := obj.(*v1alpha2.IPPool) + v1sp := obj.(*v1alpha1.IPAddressAllocation) time := metav1.Now() - v1sp.Spec.Type = "Public" v1sp.ObjectMeta.DeletionTimestamp = &time return nil }) - patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, uid interface{}) error { + patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + uid interface{}) error { assert.FailNow(t, "should not be called") return nil }) @@ -155,30 +156,28 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { // DeletionTimestamp.IsZero = false, Finalizers include util.FinalizerName k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { - v1sp := obj.(*v1alpha2.IPPool) + v1sp := obj.(*v1alpha1.IPAddressAllocation) time := metav1.Now() v1sp.ObjectMeta.DeletionTimestamp = &time - v1sp.Spec.Type = "Public" - v1sp.Finalizers = []string{common.IPPoolFinalizerName} + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, uid interface{}) error { + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, uid interface{}) error { return nil }) _, ret = r.Reconcile(ctx, req) assert.Equal(t, ret, nil) patch.Reset() - // DeletionTimestamp.IsZero = false, Finalizers include util.FinalizerName, DeleteIPPool fail + // DeletionTimestamp.IsZero = false, Finalizers include util.FinalizerName, DeleteIPAddressAllocation fail k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { - v1sp := obj.(*v1alpha2.IPPool) + v1sp := obj.(*v1alpha1.IPAddressAllocation) time := metav1.Now() - v1sp.Spec.Type = "Public" v1sp.ObjectMeta.DeletionTimestamp = &time - v1sp.Finalizers = []string{common.IPPoolFinalizerName} + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, uid interface{}) error { return errors.New("delete failed") }) @@ -188,35 +187,34 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { assert.NotEqual(t, ret, nil) patch.Reset() - // DeletionTimestamp.IsZero = true, Finalizers include util.FinalizerName, CreateorUpdateIPPool fail + // DeletionTimestamp.IsZero = true, Finalizers include util.FinalizerName, CreateorUpdateIPAddressAllocation fail k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { - v1sp := obj.(*v1alpha2.IPPool) + v1sp := obj.(*v1alpha1.IPAddressAllocation) v1sp.ObjectMeta.DeletionTimestamp = nil - v1sp.Spec.Type = "Public" - v1sp.Finalizers = []string{common.IPPoolFinalizerName} + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "CreateOrUpdateIPPool", func(_ *ippool.IPPoolService, - obj *v1alpha2.IPPool) (bool, bool, error) { - return false, false, errors.New("create failed") + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "CreateOrUpdateIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + obj *v1alpha1.IPAddressAllocation) (bool, error) { + return false, errors.New("create failed") }) - _, ret = r.Reconcile(ctx, req) + res, ret := r.Reconcile(ctx, req) + assert.Equal(t, res, resultRequeue) assert.NotEqual(t, ret, nil) patch.Reset() - // DeletionTimestamp.IsZero = true, Finalizers include util.FinalizerName, CreateorUpdateIPPool succ + // DeletionTimestamp.IsZero = true, Finalizers include util.FinalizerName, CreateorUpdateIPAddressAllocation succ k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { - v1sp := obj.(*v1alpha2.IPPool) + v1sp := obj.(*v1alpha1.IPAddressAllocation) v1sp.ObjectMeta.DeletionTimestamp = nil - v1sp.Spec.Type = "Public" - v1sp.Finalizers = []string{common.IPPoolFinalizerName} + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "CreateOrUpdateIPPool", func(_ *ippool.IPPoolService, - obj *v1alpha2.IPPool) (bool, bool, error) { - return false, false, nil + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "CreateOrUpdateIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + obj *v1alpha1.IPAddressAllocation) (bool, error) { + return true, nil }) k8sClient.EXPECT().Status().Times(1).Return(fakewriter) _, ret = r.Reconcile(ctx, req) @@ -226,7 +224,7 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { func TestReconciler_GarbageCollector(t *testing.T) { // gc collect item "2345", local store has more item than k8s cache - service := &ippool.IPPoolService{ + service := &ipaddressallocation.IPAddressAllocationService{ Service: common.Service{ NSXConfig: &config.NSXOperatorConfig{ NsxConfig: &config.NsxConfig{ @@ -235,92 +233,69 @@ func TestReconciler_GarbageCollector(t *testing.T) { }, }, } - patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "ListIPPoolID", func(_ *ippool.IPPoolService) sets.Set[string] { - a := sets.New[string]() - a.Insert("1234") - a.Insert("2345") - return a - }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, UID interface{}) error { + patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "ListIPAddressAllocationID", + func(_ *ipaddressallocation.IPAddressAllocationService) sets.Set[string] { + a := sets.New[string]() + a.Insert("1234") + a.Insert("2345") + return a + }) + patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, UID interface{}) error { return nil }) - cancel := make(chan bool) - defer patch.Reset() mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) - r := &IPPoolReconciler{ + r := &IPAddressAllocationReconciler{ Client: k8sClient, Scheme: nil, Service: service, } ctx := context.Background() - policyList := &v1alpha2.IPPoolList{} + policyList := &v1alpha1.IPAddressAllocationList{} k8sClient.EXPECT().List(gomock.Any(), policyList).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - a := list.(*v1alpha2.IPPoolList) - a.Items = append(a.Items, v1alpha2.IPPool{}) + a := list.(*v1alpha1.IPAddressAllocationList) + a.Items = append(a.Items, v1alpha1.IPAddressAllocation{}) a.Items[0].ObjectMeta = metav1.ObjectMeta{} a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.IPPoolGarbageCollector(cancel, time.Second) + r.CollectGarbage(context.Background()) // local store has same item as k8s cache patch.Reset() - patch.ApplyMethod(reflect.TypeOf(service), "ListIPPoolID", func(_ *ippool.IPPoolService) sets.Set[string] { + + patch.ApplyMethod(reflect.TypeOf(service), "ListIPAddressAllocationID", func(_ *ipaddressallocation.IPAddressAllocationService) sets.Set[string] { a := sets.New[string]() a.Insert("1234") return a }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, UID interface{}) error { + patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, UID interface{}) error { assert.FailNow(t, "should not be called") return nil }) k8sClient.EXPECT().List(ctx, policyList).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - a := list.(*v1alpha2.IPPoolList) - a.Items = append(a.Items, v1alpha2.IPPool{}) + a := list.(*v1alpha1.IPAddressAllocationList) + a.Items = append(a.Items, v1alpha1.IPAddressAllocation{}) a.Items[0].ObjectMeta = metav1.ObjectMeta{} a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.IPPoolGarbageCollector(cancel, time.Second) + r.CollectGarbage(context.Background()) // local store has no item patch.Reset() - patch.ApplyMethod(reflect.TypeOf(service), "ListIPPoolID", func(_ *ippool.IPPoolService) sets.Set[string] { + + patch.ApplyMethod(reflect.TypeOf(service), "ListIPAddressAllocationID", func(_ *ipaddressallocation.IPAddressAllocationService) sets.Set[string] { a := sets.New[string]() return a }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, UID interface{}) error { + patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, UID interface{}) error { assert.FailNow(t, "should not be called") return nil }) k8sClient.EXPECT().List(ctx, policyList).Return(nil).Times(0) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.IPPoolGarbageCollector(cancel, time.Second) -} + r.CollectGarbage(context.Background()) -func TestReconciler_Start(t *testing.T) { - mockCtl := gomock.NewController(t) - k8sClient := mock_client.NewMockClient(mockCtl) - service := &ippool.IPPoolService{} - var mgr controllerruntime.Manager - r := &IPPoolReconciler{ - Client: k8sClient, - Scheme: nil, - Service: service, - } - err := r.Start(mgr) - assert.NotEqual(t, err, nil) + patch.Reset() } diff --git a/pkg/controllers/ippool/ippool_controller.go b/pkg/controllers/ippool/ippool_controller.go deleted file mode 100644 index a5d0b52e8..000000000 --- a/pkg/controllers/ippool/ippool_controller.go +++ /dev/null @@ -1,307 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package ippool - -import ( - "context" - "fmt" - "regexp" - "time" - - "github.com/pkg/errors" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apimachineryruntime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/predicate" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" - "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" - "github.com/vmware-tanzu/nsx-operator/pkg/logger" - "github.com/vmware-tanzu/nsx-operator/pkg/metrics" - servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ippool" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" - util2 "github.com/vmware-tanzu/nsx-operator/pkg/util" -) - -var ( - log = logger.Log - resultNormal = common.ResultNormal - resultRequeue = common.ResultRequeue - MetricResType = common.MetricResTypeIPPool -) - -// IPPoolReconciler reconciles a IPPool object -type IPPoolReconciler struct { - client.Client - Scheme *apimachineryruntime.Scheme - Service *ippool.IPPoolService - VPCService servicecommon.VPCServiceProvider - Recorder record.EventRecorder -} - -func deleteSuccess(r *IPPoolReconciler, _ *context.Context, o *v1alpha2.IPPool) { - r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "IPPool CR has been successfully deleted") - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) -} - -func deleteFail(r *IPPoolReconciler, c *context.Context, o *v1alpha2.IPPool, e *error) { - r.setReadyStatusFalse(c, o, metav1.Now(), e) - r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) -} - -func updateSuccess(r *IPPoolReconciler, c *context.Context, o *v1alpha2.IPPool) { - r.setReadyStatusTrue(c, o, metav1.Now()) - r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "IPPool CR has been successfully updated") - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) -} - -func updateFail(r *IPPoolReconciler, c *context.Context, o *v1alpha2.IPPool, e *error) { - r.setReadyStatusFalse(c, o, metav1.Now(), e) - r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) -} - -func (r *IPPoolReconciler) setReadyStatusFalse(ctx *context.Context, ippool *v1alpha2.IPPool, transitionTime metav1.Time, err *error) { - conditions := []v1alpha1.Condition{ - { - Type: v1alpha1.Ready, - Status: v1.ConditionFalse, - Message: "NSX IPPool could not be created/updated/deleted", - Reason: fmt.Sprintf( - "error occurred while processing the IPPool CR. Error: %v", - *err, - ), - LastTransitionTime: transitionTime, - }, - } - ippool.Status.Conditions = conditions - if ippool.Status.Subnets == nil { - ippool.Status.Subnets = make([]v1alpha2.SubnetResult, 0) - } - e := r.Client.Status().Update(*ctx, ippool) - if e != nil { - log.Error(e, "unable to update IPPool status", "ippool", ippool) - } -} - -func (r *IPPoolReconciler) setReadyStatusTrue(ctx *context.Context, ippool *v1alpha2.IPPool, transitionTime metav1.Time) { - conditions := []v1alpha1.Condition{ - { - Type: v1alpha1.Ready, - Status: v1.ConditionTrue, - Message: "NSX IPPool has been successfully created/updated", - Reason: "", - LastTransitionTime: transitionTime, - }, - } - ippool.Status.Conditions = conditions - e := r.Client.Status().Update(*ctx, ippool) - if e != nil { - log.Error(e, "unable to update IPPool status", "ippool", ippool) - } -} - -func (r *IPPoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - obj := &v1alpha2.IPPool{} - log.Info("reconciling ippool CR", "ippool", req.NamespacedName) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) - if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { - log.Error(err, "unable to fetch ippool CR", "req", req.NamespacedName) - return resultNormal, client.IgnoreNotFound(err) - } - - // TODO: As we do not have base controller in Go, we need to take care of NSX exceptions in each controller separately. - //I agree we should not do infinite retry for all errors, but it's ok to add error handling in a following patch - - // TODO: Since only the cloud provider creates it, we can take all the validation logic into consideration later. - - // TODO: add webhook to disallow user update prefixLength - - // TODO: Tao's suggestions: Should we consider some Orphan subnets may exist? - - // TODO: Xiaopei's suggestions: is there possibility that IPPool was deleted from nsx store but NSX block subnet was not deleted? - - if obj.Spec.Type == "" { - vpcNetworkConfig := r.VPCService.GetVPCNetworkConfigByNamespace(obj.Namespace) - if vpcNetworkConfig == nil { - err := fmt.Errorf("operate failed: cannot get configuration for IPPool CR") - log.Error(err, "failed to find VPCNetworkConfig for IPPool CR", "ippool", req.NamespacedName, "namespace %s", obj.Namespace) - updateFail(r, &ctx, obj, &err) - return resultRequeue, err - } - obj.Spec.Type = vpcNetworkConfig.DefaultSubnetAccessMode - } - - if obj.ObjectMeta.DeletionTimestamp.IsZero() { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType) - if !controllerutil.ContainsFinalizer(obj, servicecommon.IPPoolFinalizerName) { - controllerutil.AddFinalizer(obj, servicecommon.IPPoolFinalizerName) - if err := r.Client.Update(ctx, obj); err != nil { - log.Error(err, "add finalizer", "ippool", req.NamespacedName) - updateFail(r, &ctx, obj, &err) - return resultRequeue, err - } - log.V(1).Info("added finalizer on ippool CR", "ippool", req.NamespacedName) - } - - subnetCidrUpdated, ipPoolSubnetsUpdated, err := r.Service.CreateOrUpdateIPPool(obj) - // check if ipblock is exhausted - apiErr, _ := util.DumpAPIError(err) - if apiErr != nil { - for _, apiErrItem := range apiErr.RelatedErrors { - // 520012=IpAddressBlock with max size does not have spare capacity to satisfy new block subnet of size - if *apiErrItem.ErrorCode == 520012 { - pathPattern := `path=\[([^\]]+)\]` - pathRegex := regexp.MustCompile(pathPattern) - pathMatch := pathRegex.FindStringSubmatch(*apiErrItem.ErrorMessage) - if len(pathMatch) > 1 { - path := pathMatch[1] - if !util2.Contains(r.Service.ExhaustedIPBlock, path) { - r.Service.ExhaustedIPBlock = append(r.Service.ExhaustedIPBlock, path) - log.Info("ExhaustedIPBlock: ", "ExhaustedIPBlock", r.Service.ExhaustedIPBlock) - } - } - } - } - } - - if err != nil { - updateFail(r, &ctx, obj, &err) - // if all ip blocks are exhausted, we should not retry - if errors.As(err, &util.IPBlockAllExhaustedError{}) { - log.Error(err, "ip blocks are all exhausted, would retry exponentially", "ippool", req.NamespacedName) - r.Service.ExhaustedIPBlock = []string{} - log.Info("Clear ExhaustedIPBlock: ", "ExhaustedIPBlock", r.Service.ExhaustedIPBlock) - return common.ResultRequeueAfter10sec, err - } - log.Error(err, "operate failed, would retry exponentially", "ippool", req.NamespacedName) - return resultRequeue, err - } - if !r.Service.FullyRealized(obj) { - if len(obj.Spec.Subnets) == 0 { - updateSuccess(r, &ctx, obj) - return resultNormal, nil - } - if subnetCidrUpdated || ipPoolSubnetsUpdated { - err := fmt.Errorf("partial subnets are unrealized, would retry exponentially") - updateFail(r, &ctx, obj, &err) - log.Info("successfully reconcile ippool CR, but put back ippool again, since partial subnets are unrealized", "subnets", - r.Service.GetUnrealizedSubnetNames(obj)) - return resultRequeue, nil - } - } else { - if subnetCidrUpdated || ipPoolSubnetsUpdated || len(obj.Spec.Subnets) == 0 { - updateSuccess(r, &ctx, obj) - log.Info("successfully reconcile ippool CR and all subnets are fully realized", "ippool", obj) - } else { - log.Info("full realized already, and resources are not changed, skip updating them", "obj", obj) - } - } - } else { - if controllerutil.ContainsFinalizer(obj, servicecommon.IPPoolFinalizerName) { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) - if err := r.Service.DeleteIPPool(obj); err != nil { - log.Error(err, "deletion failed, would retry exponentially", "ippool", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) - return resultRequeue, err - } - controllerutil.RemoveFinalizer(obj, servicecommon.IPPoolFinalizerName) - if err := r.Client.Update(ctx, obj); err != nil { - log.Error(err, "deletion failed, would retry exponentially", "ippool", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) - return resultRequeue, err - } - log.V(1).Info("removed finalizer on ippool CR", "ippool", req.NamespacedName) - deleteSuccess(r, &ctx, obj) - log.Info("successfully deleted ippool CR and all subnets", "ippool", obj) - } else { - // only print a message because it's not a normal case - log.Info("ippool CR is being deleted but its finalizers cannot be recognized", "ippool", req.NamespacedName) - } - } - return resultNormal, nil -} - -func (r *IPPoolReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha2.IPPool{}). - WithEventFilter(predicate.Funcs{ - UpdateFunc: func(e event.UpdateEvent) bool { - // Ignore updates to CR status in which case metadata.Generation does not change - return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration() - }, - DeleteFunc: func(e event.DeleteEvent) bool { - // Suppress Delete events to avoid filtering them out in the Reconcile function - return false - }, - }). - WithOptions( - controller.Options{ - MaxConcurrentReconciles: common.NumReconcile(), - }). - Complete(r) -} - -// Start setup manager and launch GC -func (r *IPPoolReconciler) Start(mgr ctrl.Manager) error { - err := r.SetupWithManager(mgr) - if err != nil { - return err - } - go r.IPPoolGarbageCollector(make(chan bool), servicecommon.GCInterval) - return nil -} - -// IPPoolGarbageCollector collect ippool which has been removed from crd. -// cancel is used to break the loop during UT -func (r *IPPoolReconciler) IPPoolGarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("ippool garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxIPPoolSet := r.Service.ListIPPoolID() - if len(nsxIPPoolSet) == 0 { - continue - } - ipPoolList := &v1alpha2.IPPoolList{} - err := r.Client.List(ctx, ipPoolList) - if err != nil { - log.Error(err, "failed to list ip pool CR") - continue - } - - CRIPPoolSet := sets.NewString() - for _, ipp := range ipPoolList.Items { - CRIPPoolSet.Insert(string(ipp.UID)) - } - - log.V(2).Info("ippool garbage collector", "nsxIPPoolSet", nsxIPPoolSet, "CRIPPoolSet", CRIPPoolSet) - - for elem := range nsxIPPoolSet { - if CRIPPoolSet.Has(elem) { - continue - } - log.Info("GC collected ip pool CR", "UID", elem) - err = r.Service.DeleteIPPool(types.UID(elem)) - if err != nil { - log.Error(err, "failed to delete ip pool CR", "UID", elem) - } - } - } -} diff --git a/pkg/controllers/namespace/builder.go b/pkg/controllers/namespace/builder.go deleted file mode 100644 index 4ee82d27a..000000000 --- a/pkg/controllers/namespace/builder.go +++ /dev/null @@ -1,20 +0,0 @@ -package namespace - -import ( - "github.com/google/uuid" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" -) - -func BuildVPCCR(ns string, ncName string, vpcName *string) *v1alpha1.VPC { - log.V(2).Info("building vpc", "ns", ns, "nc", ncName, "VPC", vpcName) - vpc := &v1alpha1.VPC{} - if vpcName == nil { - vpc.Name = "vpc-" + uuid.New().String() - } else { - vpc.Name = *vpcName - } - - vpc.Namespace = ns - return vpc -} diff --git a/pkg/controllers/namespace/builder_test.go b/pkg/controllers/namespace/builder_test.go deleted file mode 100644 index 6d362ead1..000000000 --- a/pkg/controllers/namespace/builder_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package namespace - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBuildVPCCR(t *testing.T) { - vpcName := "fake-vpc" - tests := []struct { - name string - ns string - nc string - vpcName *string - }{ - {"1", "test-ns1", "test-nc1", nil}, - {"2", "test-ns2", "test-nc2", &vpcName}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - vpc := BuildVPCCR(tt.ns, tt.nc, tt.vpcName) - if tt.vpcName == nil { - assert.True(t, strings.Contains(vpc.Name, "vpc-")) - } else { - assert.Equal(t, *tt.vpcName, vpc.Name) - } - - assert.Equal(t, tt.ns, vpc.Namespace) - }) - } -} diff --git a/pkg/controllers/namespace/namespace_controller.go b/pkg/controllers/namespace/namespace_controller.go index ce33b661d..a46267963 100644 --- a/pkg/controllers/namespace/namespace_controller.go +++ b/pkg/controllers/namespace/namespace_controller.go @@ -7,7 +7,6 @@ import ( "context" "errors" "fmt" - "strings" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -17,7 +16,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -29,8 +28,7 @@ import ( var ( AnnotationNamespaceVPCError = " nsx.vmware.com/vpc_error" - - log = logger.Log + log = &logger.Log ) // NamespaceReconciler process namespace create/delete event @@ -51,35 +49,29 @@ func (r *NamespaceReconciler) getDefaultNetworkConfigName() (string, error) { return nc.Name, nil } -func (r *NamespaceReconciler) createVPCCR(ctx *context.Context, obj client.Object, ns string, ncName string, vpcName *string) (*v1alpha1.VPC, error) { - // check if vpc cr already exist under this namespace - vpcs := &v1alpha1.VPCList{} - r.Client.List(*ctx, vpcs, client.InNamespace(ns)) - if len(vpcs.Items) > 0 { - // if there is already one vpc exist under this ns, return this vpc. - log.Info("vpc cr already exist, skip creating", "VPC", vpcs.Items[0].Name) - return &vpcs.Items[0], nil - } - nc, ncExist := r.VPCService.GetVPCNetworkConfig(ncName) - if !ncExist { - message := fmt.Sprintf("missing network config %s for namespace %s", ncName, ns) - r.namespaceError(ctx, obj, message, nil) - return nil, errors.New(message) - } - if !r.VPCService.ValidateNetworkConfig(nc) { - // if network config is not valid, no need to retry, skip processing - message := fmt.Sprintf("invalid network config %s for namespace %s, missing private cidr", ncName, ns) - r.namespaceError(ctx, obj, message, nil) - return nil, errors.New(message) +func (r *NamespaceReconciler) createNetworkInfoCR(ctx context.Context, obj client.Object, ns string) (*v1alpha1.NetworkInfo, error) { + networkInfos := &v1alpha1.NetworkInfoList{} + r.Client.List(ctx, networkInfos, client.InNamespace(ns)) + if len(networkInfos.Items) > 0 { + // if there is already one networkInfo, return this networkInfo + log.Info("networkInfo already exists", "networkInfo", networkInfos.Items[0].Name, "Namespace", ns) + return &networkInfos.Items[0], nil } - // create vpc cr with existing vpc network config - vpcCR := BuildVPCCR(ns, ncName, vpcName) - err := r.Client.Create(*ctx, vpcCR) + // create networkInfo cr with existing vpc network config + log.V(2).Info("building networkInfo", "ns", ns) + networkInfoCR := &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Name: ns, + Namespace: ns, + }, + VPCs: []v1alpha1.VPCState{}, + } + err := r.Client.Create(ctx, networkInfoCR) if err != nil { - message := "failed to create VPC CR" + message := "failed to create NetworkInfo CR" r.namespaceError(ctx, obj, message, err) - // If create VPC CR failed, put ns create event back to queue. + // If create NetworkInfo CR failed, put ns create event back to queue. return nil, err } @@ -87,11 +79,12 @@ func (r *NamespaceReconciler) createVPCCR(ctx *context.Context, obj client.Objec AnnotationNamespaceVPCError: "", } util.UpdateK8sResourceAnnotation(r.Client, ctx, obj, changes) - log.Info("create VPC CR", "VPC", vpcCR.Name, "Namespace", vpcCR.Namespace) - return vpcCR, nil + + log.Info("create NetworkInfo CR", "NetworkInfo", networkInfoCR.Name, "Namespace", networkInfoCR.Namespace) + return networkInfoCR, nil } -func (r *NamespaceReconciler) createDefaultSubnetSet(ns string) error { +func (r *NamespaceReconciler) createDefaultSubnetSet(ns string, defaultSubnetSize int) error { defaultSubnetSets := map[string]string{ types.DefaultVMSubnetSet: types.LabelDefaultVMSubnetSet, types.DefaultPodSubnetSet: types.LabelDefaultPodSubnetSet, @@ -119,14 +112,14 @@ func (r *NamespaceReconciler) createDefaultSubnetSet(ns string) error { types.LabelDefaultSubnetSet: subnetSetType, }, }, - Spec: v1alpha1.SubnetSetSpec{ - AdvancedConfig: v1alpha1.AdvancedConfig{ - StaticIPAllocation: v1alpha1.StaticIPAllocation{ - Enable: true, - }, - }, - }, + Spec: v1alpha1.SubnetSetSpec{}, } + if name == types.DefaultVMSubnetSet { + obj.Spec.AccessMode = v1alpha1.AccessMode(v1alpha1.AccessModePrivate) + } else if name == types.DefaultPodSubnetSet { + obj.Spec.AccessMode = v1alpha1.AccessMode(v1alpha1.AccessModeProject) + } + obj.Spec.IPv4SubnetSize = defaultSubnetSize if err := r.Client.Create(context.Background(), obj); err != nil { return err } @@ -139,7 +132,7 @@ func (r *NamespaceReconciler) createDefaultSubnetSet(ns string) error { return nil } -func (r *NamespaceReconciler) namespaceError(ctx *context.Context, k8sObj client.Object, msg string, err error) { +func (r *NamespaceReconciler) namespaceError(ctx context.Context, k8sObj client.Object, msg string, err error) { logErr := util.If(err == nil, errors.New(msg), err).(error) log.Error(logErr, msg) changes := map[string]string{AnnotationNamespaceVPCError: msg} @@ -178,12 +171,12 @@ func (r *NamespaceReconciler) insertNamespaceNetworkconfigBinding(ns string, ann VPC creation strategy: We suppose namespace should have following annotations: - - "nsx.vmware.com/vpc_name": "/" - If the ns contains this annotation, first check if the namespace in annotation is the same as + - "nsx.vmware.com/shared_vpc_namespace": "" + If the ns contains this annotation, first check if the namespace in annotation is the same as the one in ns event, if yes, create an infra VPC for it. if not, skip the whole ns event as the infra VPC will be created its corresponding ns creation event. - "nsx.vmware.com/vpc_network_config":"" - If ns do not contains "nsx.vmware.com/vpc_name" annotation. Use this annotation to handle VPC creation. + If ns do not contains "nsx.vmware.com/shared_vpc_namespace" annotation. Use this annotation to handle VPC creation. VPC will locate the network config with the CR name, and create VPC using its config. - If the ns do not have either of the annotation above, then we believe it is using default VPC, try to search default VPC in network config CR store. The default VPC network config CR's name is "default". @@ -211,31 +204,7 @@ func (r *NamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( log.Error(err, "failed to build namespace and network config bindings", "Namepspace", ns) return common.ResultRequeueAfter10sec, nil } - // read anno "nsx.vmware.com/vpc_name", if ns contains this annotation, it means it will share - // infra VPC, if the ns in the annotation is the same as ns event, create infra VPC, if not, - // skip the event. ncName, ncExist := annotations[types.AnnotationVPCNetworkConfig] - vpcName, nameExist := annotations[types.AnnotationVPCName] - var createVpcName *string - if nameExist { - log.Info("read ns annotation vpcName", "VPCNAME", vpcName) - res := strings.Split(vpcName, "/") - // The format should be namespace/vpc_name - if len(res) != 2 { - message := fmt.Sprintf("incorrect vpcName annotation %s for namespace %s", vpcName, ns) - r.namespaceError(&ctx, obj, message, nil) - // If illegal format, skip handling this event? - return common.ResultNormal, nil - } - log.Info("start to handle vpcName anno", "VPCNS", res[1], "NS", ns) - - if ns != res[0] { - log.Info("name space is using shared vpc, with vpc name anno", "VPCNAME", vpcName, "Namespace", ns) - return common.ResultNormal, nil - } - createVpcName = &res[1] - log.Info("creating vpc using customer defined vpc name", "VPCName", res[1]) - } // If ns do not have network config name tag, then use default vpc network config name if !ncExist { @@ -247,10 +216,23 @@ func (r *NamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } } - if _, err := r.createVPCCR(&ctx, obj, ns, ncName, createVpcName); err != nil { + nc, ncExist := r.VPCService.GetVPCNetworkConfig(ncName) + if !ncExist { + message := fmt.Sprintf("missing network config %s for namespace %s", ncName, ns) + r.namespaceError(ctx, obj, message, nil) + return common.ResultRequeueAfter10sec, nil + } + if !r.VPCService.ValidateNetworkConfig(nc) { + // if network config is not valid, no need to retry, skip processing + message := fmt.Sprintf("invalid network config %s for namespace %s, missing private cidr", ncName, ns) + r.namespaceError(ctx, obj, message, nil) + return common.ResultRequeueAfter10sec, nil + } + + if _, err := r.createNetworkInfoCR(ctx, obj, ns); err != nil { return common.ResultRequeueAfter10sec, nil } - if err := r.createDefaultSubnetSet(ns); err != nil { + if err := r.createDefaultSubnetSet(ns, nc.DefaultSubnetSize); err != nil { return common.ResultRequeueAfter10sec, nil } return common.ResultNormal, nil diff --git a/pkg/controllers/namespace/namespace_controller_test.go b/pkg/controllers/namespace/namespace_controller_test.go index 834b3e88f..9053d0797 100644 --- a/pkg/controllers/namespace/namespace_controller_test.go +++ b/pkg/controllers/namespace/namespace_controller_test.go @@ -4,31 +4,19 @@ package namespace import ( - "context" "errors" "reflect" "testing" "github.com/agiledragon/gomonkey/v2" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" - mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" - "github.com/vmware-tanzu/nsx-operator/pkg/util" -) - -var ( - BuildVPCCRFunc = BuildVPCCR ) func createNameSpaceReconciler() *NamespaceReconciler { @@ -43,8 +31,12 @@ func createNameSpaceReconciler() *NamespaceReconciler { }, }, }, - VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, - VPCNSNetworkConfigMap: map[string]string{}, + VPCNetworkConfigStore: vpc.VPCNetworkInfoStore{ + VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, + }, + VPCNSNetworkConfigStore: vpc.VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: map[string]string{}, + }, } return &NamespaceReconciler{ @@ -121,111 +113,3 @@ func TestInsertNamespaceNetworkconfigBinding(t *testing.T) { }) } } - -func TestCreateVPCCR(t *testing.T) { - r := createNameSpaceReconciler() - mockCtl := gomock.NewController(t) - k8sClient := mock_client.NewMockClient(mockCtl) - ctx := context.Background() - r.Client = k8sClient - namespace := v1.Namespace{} - vpcList1 := &v1alpha1.VPCList{Items: []v1alpha1.VPC{{ObjectMeta: metav1.ObjectMeta{Name: "fake-name1"}}, {}}} - vpcs := &v1alpha1.VPCList{} - k8sClient.EXPECT().List(gomock.Any(), vpcs, client.InNamespace("test-ns")).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - list.(*v1alpha1.VPCList).Items = vpcList1.Items - return nil - }) - target, err := r.createVPCCR(&ctx, &namespace, "test-ns", "test-nc", nil) - assert.Equal(t, target.Name, "fake-name1") - assert.Nil(t, err) - - vpcs = &v1alpha1.VPCList{} - k8sClient.EXPECT().List(gomock.Any(), vpcs, client.InNamespace("test-ns")).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - list.(*v1alpha1.VPCList).Items = []v1alpha1.VPC{} - return nil - }) - patch1 := gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "GetVPCNetworkConfig", func(_ *vpc.VPCService, ncName string) (common.VPCNetworkConfigInfo, bool) { - return common.VPCNetworkConfigInfo{}, false - }) - patch2 := gomonkey.ApplyPrivateMethod(reflect.TypeOf(r), "namespaceError", func(_ *NamespaceReconciler, _ *context.Context, _ client.Object, _ string, _ error) { - }) - target, err = r.createVPCCR(&ctx, &namespace, "test-ns", "test-nc", nil) - assert.Nil(t, target) - assert.NotNil(t, err) - patch1.Reset() - patch2.Reset() - - vpcs = &v1alpha1.VPCList{} - k8sClient.EXPECT().List(gomock.Any(), vpcs, client.InNamespace("test-ns")).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - list.(*v1alpha1.VPCList).Items = []v1alpha1.VPC{} - return nil - }) - patch1 = gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "GetVPCNetworkConfig", func(_ *vpc.VPCService, ncName string) (common.VPCNetworkConfigInfo, bool) { - return common.VPCNetworkConfigInfo{}, true - }) - patch2 = gomonkey.ApplyPrivateMethod(reflect.TypeOf(r), "namespaceError", func(_ *NamespaceReconciler, _ *context.Context, _ client.Object, _ string, _ error) { - }) - patch3 := gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "ValidateNetworkConfig", func(_ *vpc.VPCService, nc common.VPCNetworkConfigInfo) bool { - return false - }) - target, err = r.createVPCCR(&ctx, &namespace, "test-ns", "test-nc", nil) - assert.Nil(t, target) - assert.NotNil(t, err) - patch1.Reset() - patch2.Reset() - patch3.Reset() - - vpcs = &v1alpha1.VPCList{} - mockVPC := &v1alpha1.VPC{} - mockVPC.SetName("test-vpc") - buildVPCPatch := gomonkey.ApplyFuncReturn(BuildVPCCR, mockVPC) - - k8sClient.EXPECT().List(gomock.Any(), vpcs, client.InNamespace("test-ns")).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - list.(*v1alpha1.VPCList).Items = []v1alpha1.VPC{} - return nil - }) - k8sClient.EXPECT().Create(gomock.Any(), mockVPC, gomock.Any()).Return(errors.New("create-err")).Do(func(_ context.Context, _ client.Object, _ ...client.CreateOption) error { - return errors.New("create vpc cr error") - }) - patch1 = gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "GetVPCNetworkConfig", func(_ *vpc.VPCService, ncName string) (common.VPCNetworkConfigInfo, bool) { - return common.VPCNetworkConfigInfo{}, true - }) - patch2 = gomonkey.ApplyPrivateMethod(reflect.TypeOf(r), "namespaceError", func(_ *NamespaceReconciler, _ *context.Context, _ client.Object, _ string, _ error) { - }) - patch3 = gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "ValidateNetworkConfig", func(_ *vpc.VPCService, nc common.VPCNetworkConfigInfo) bool { - return true - }) - target, err = r.createVPCCR(&ctx, &namespace, "test-ns", "test-nc", nil) - assert.Nil(t, target) - assert.NotNil(t, err) - patch1.Reset() - patch2.Reset() - patch3.Reset() - - vpcs = &v1alpha1.VPCList{} - k8sClient.EXPECT().List(gomock.Any(), vpcs, client.InNamespace("test-ns")).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - list.(*v1alpha1.VPCList).Items = []v1alpha1.VPC{} - return nil - }) - k8sClient.EXPECT().Create(gomock.Any(), mockVPC, gomock.Any()).Return(nil).Do(func(_ context.Context, _ client.Object, _ ...client.CreateOption) error { - return nil - }) - patch1 = gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "GetVPCNetworkConfig", func(_ *vpc.VPCService, ncName string) (common.VPCNetworkConfigInfo, bool) { - return common.VPCNetworkConfigInfo{}, true - }) - patch2 = gomonkey.ApplyPrivateMethod(reflect.TypeOf(r), "namespaceError", func(_ *NamespaceReconciler, _ *context.Context, _ client.Object, _ string, _ error) { - }) - patch3 = gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "ValidateNetworkConfig", func(_ *vpc.VPCService, nc common.VPCNetworkConfigInfo) bool { - return true - }) - patchUtil := gomonkey.ApplyFuncReturn(util.UpdateK8sResourceAnnotation, nil) - target, err = r.createVPCCR(&ctx, &namespace, "test-ns", "test-nc", nil) - assert.Equal(t, target.GetName(), "test-vpc") - assert.Nil(t, err) - - patch1.Reset() - patch2.Reset() - patch3.Reset() - buildVPCPatch.Reset() - patchUtil.Reset() -} diff --git a/pkg/controllers/networkinfo/networkinfo_controller.go b/pkg/controllers/networkinfo/networkinfo_controller.go new file mode 100644 index 000000000..694e69375 --- /dev/null +++ b/pkg/controllers/networkinfo/networkinfo_controller.go @@ -0,0 +1,343 @@ +/* Copyright © 2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package networkinfo + +import ( + "context" + "errors" + "fmt" + + corev1 "k8s.io/api/core/v1" + apimachineryruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" + "github.com/vmware-tanzu/nsx-operator/pkg/logger" + "github.com/vmware-tanzu/nsx-operator/pkg/metrics" + _ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" + commonservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" +) + +var ( + log = &logger.Log + MetricResType = common.MetricResTypeNetworkInfo +) + +// NetworkInfoReconciler NetworkInfoReconcile reconciles a NetworkInfo object +// Actually it is more like a shell, which is used to manage nsx VPC +type NetworkInfoReconciler struct { + Client client.Client + Scheme *apimachineryruntime.Scheme + Service *vpc.VPCService + Recorder record.EventRecorder +} + +func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := &v1alpha1.NetworkInfo{} + log.Info("reconciling NetworkInfo CR", "NetworkInfo", req.NamespacedName) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, common.MetricResTypeNetworkInfo) + + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + log.Error(err, "unable to fetch NetworkInfo CR", "req", req.NamespacedName) + return common.ResultNormal, client.IgnoreNotFound(err) + } + if obj.ObjectMeta.DeletionTimestamp.IsZero() { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, common.MetricResTypeNetworkInfo) + if !controllerutil.ContainsFinalizer(obj, commonservice.NetworkInfoFinalizerName) { + controllerutil.AddFinalizer(obj, commonservice.NetworkInfoFinalizerName) + if err := r.Client.Update(ctx, obj); err != nil { + log.Error(err, "add finalizer", "NetworkInfo", req.NamespacedName) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeue, err + } + log.V(1).Info("added finalizer on NetworkInfo CR", "NetworkInfo", req.NamespacedName) + } + // TODO: + // 1. check whether the logic to get VPC network config can be replaced by GetVPCNetworkConfigByNamespace + // 2. sometimes the variable nc points to a VPCNetworkInfo, sometimes it's a VPCNetworkConfiguration, we need to distinguish between them. + ncName, err := r.Service.GetNetworkconfigNameFromNS(obj.Namespace) + if err != nil { + log.Error(err, "failed to get network config name for VPC when creating NSX VPC", "VPC", obj.Name) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, err + } + nc, _exist := r.Service.GetVPCNetworkConfig(ncName) + if !_exist { + message := fmt.Sprintf("failed to read network config %s when creating NSX VPC", ncName) + log.Info(message) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, errors.New(message) + } + log.Info("got network config from store", "NetworkConfig", ncName) + vpcNetworkConfiguration := &v1alpha1.VPCNetworkConfiguration{} + err = r.Client.Get(ctx, types.NamespacedName{Name: commonservice.SystemVPCNetworkConfigurationName}, vpcNetworkConfiguration) + if err != nil { + log.Error(err, "failed to get system VPCNetworkConfiguration") + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, err + } + gatewayConnectionReady, _, err := getGatewayConnectionStatus(ctx, vpcNetworkConfiguration) + if err != nil { + log.Error(err, "failed to get the gateway connection status", "req", req.NamespacedName) + return common.ResultRequeueAfter10sec, err + } + + reason := "" + if !gatewayConnectionReady { + if ncName == commonservice.SystemVPCNetworkConfigurationName { + gatewayConnectionReady, reason, err = r.Service.ValidateGatewayConnectionStatus(&nc) + log.Info("got the gateway connection status", "gatewayConnectionReady", gatewayConnectionReady, "reason", reason) + if err != nil { + log.Error(err, "failed to validate the edge and gateway connection", "org", nc.Org, "project", nc.NSXProject) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, err + } + setVPCNetworkConfigurationStatusWithGatewayConnection(ctx, r.Client, vpcNetworkConfiguration, gatewayConnectionReady, reason) + } else { + log.Info("skipping reconciling the network info because the system gateway connection is not ready", "NetworkInfo", req.NamespacedName) + return common.ResultRequeueAfter60sec, nil + } + } + + createdVpc, err := r.Service.CreateOrUpdateVPC(obj, &nc) + if err != nil { + log.Error(err, "create vpc failed, would retry exponentially", "VPC", req.NamespacedName) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, err + } + + var privateIPs []string + var vpcConnectivityProfilePath string + if vpc.IsPreCreatedVPC(nc) { + privateIPs = createdVpc.PrivateIps + vpcConnectivityProfilePath = *createdVpc.VpcConnectivityProfile + } else { + privateIPs = nc.PrivateIPs + vpcConnectivityProfilePath = nc.VPCConnectivityProfile + } + + snatIP, path, cidr := "", "", "" + + vpcConnectivityProfile, err := r.Service.GetVpcConnectivityProfile(&nc, vpcConnectivityProfilePath) + if err != nil { + log.Error(err, "get VpcConnectivityProfile failed, would retry exponentially", "VPC", req.NamespacedName) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, err + } + + if ncName == commonservice.SystemVPCNetworkConfigurationName { + if len(vpcConnectivityProfile.ExternalIpBlocks) == 0 { + setVPCNetworkConfigurationStatusWithNoExternalIPBlock(ctx, r.Client, vpcNetworkConfiguration, false) + log.Error(err, "there is no ExternalIPBlock in VPC ConnectivityProfile", "VPC", req.NamespacedName) + } else { + setVPCNetworkConfigurationStatusWithNoExternalIPBlock(ctx, r.Client, vpcNetworkConfiguration, true) + } + } + isEnableAutoSNAT := func() bool { + if vpcConnectivityProfile.ServiceGateway == nil || vpcConnectivityProfile.ServiceGateway.Enable == nil { + return false + } + if *vpcConnectivityProfile.ServiceGateway.Enable { + if vpcConnectivityProfile.ServiceGateway.NatConfig == nil || vpcConnectivityProfile.ServiceGateway.NatConfig.EnableDefaultSnat == nil { + return false + } + return *vpcConnectivityProfile.ServiceGateway.NatConfig.EnableDefaultSnat + } + return false + } + // currently, auto snat is not exposed, and use default value True + // checking autosnat to support future extension in vpc configuration + autoSnatEnabled := isEnableAutoSNAT() + if autoSnatEnabled { + snatIP, err = r.Service.GetDefaultSNATIP(*createdVpc) + if err != nil { + log.Error(err, "failed to read default SNAT ip from VPC", "VPC", createdVpc.Id) + state := &v1alpha1.VPCState{ + Name: *createdVpc.DisplayName, + DefaultSNATIP: "", + LoadBalancerIPAddresses: "", + PrivateIPs: privateIPs, + } + updateFail(r, ctx, obj, &err, r.Client, state) + return common.ResultRequeueAfter10sec, err + } + } + if ncName == commonservice.SystemVPCNetworkConfigurationName { + vpcNetworkConfiguration := &v1alpha1.VPCNetworkConfiguration{} + err := r.Client.Get(ctx, types.NamespacedName{Name: ncName}, vpcNetworkConfiguration) + if err != nil { + log.Error(err, "failed to get VPCNetworkConfiguration", "Name", ncName) + updateFail(r, ctx, obj, &err, r.Client, nil) + return common.ResultRequeueAfter10sec, err + } + if autoSnatEnabled { + log.Info("detected that the AutoSnat is enabled", "req", req.NamespacedName) + setVPCNetworkConfigurationStatusWithSnatEnabled(ctx, r.Client, vpcNetworkConfiguration, true) + } else { + log.Info("detected that the AutoSnat is disabled", "req", req.NamespacedName) + setVPCNetworkConfigurationStatusWithSnatEnabled(ctx, r.Client, vpcNetworkConfiguration, false) + } + } + + // if lb vpc enabled, read avi subnet path and cidr + // nsx bug, if set LoadBalancerVpcEndpoint.Enabled to false, when read this vpc back, + // LoadBalancerVpcEndpoint.Enabled will become a nil pointer. + if !r.Service.NSXLBEnabled() && createdVpc.LoadBalancerVpcEndpoint.Enabled != nil && *createdVpc.LoadBalancerVpcEndpoint.Enabled { + path, cidr, err = r.Service.GetAVISubnetInfo(*createdVpc) + if err != nil { + log.Error(err, "failed to read lb subnet path and cidr", "VPC", createdVpc.Id) + state := &v1alpha1.VPCState{ + Name: *createdVpc.DisplayName, + DefaultSNATIP: snatIP, + LoadBalancerIPAddresses: "", + PrivateIPs: privateIPs, + } + updateFail(r, ctx, obj, &err, r.Client, state) + return common.ResultRequeueAfter10sec, err + } + } + + state := &v1alpha1.VPCState{ + Name: *createdVpc.DisplayName, + DefaultSNATIP: snatIP, + LoadBalancerIPAddresses: cidr, + PrivateIPs: privateIPs, + VPCPath: *createdVpc.Path, + } + // AKO needs to know the AVI subnet path created by NSX + setVPCNetworkConfigurationStatusWithLBS(ctx, r.Client, ncName, state.Name, path, r.Service.GetNSXLBSPath(*createdVpc.Id), *createdVpc.Path) + updateSuccess(r, ctx, obj, r.Client, state, nc.Name, path) + } else { + if controllerutil.ContainsFinalizer(obj, commonservice.NetworkInfoFinalizerName) { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeNetworkInfo) + isShared, err := r.Service.IsSharedVPCNamespaceByNS(obj.GetNamespace()) + if err != nil { + log.Error(err, "failed to check if namespace is shared", "Namespace", obj.GetNamespace()) + return common.ResultRequeue, err + } + vpcs := r.Service.GetVPCsByNamespace(obj.GetNamespace()) + // if nsx resource do not exist, continue to remove finalizer, or the crd can not be removed + if len(vpcs) == 0 { + // when nsx vpc not found in vpc store, skip deleting NSX VPC + log.Info("can not find VPC in store, skip deleting NSX VPC, remove finalizer from NetworkInfo CR") + } else if !isShared { + for _, vpc := range vpcs { + // first delete vpc and then ipblock or else it will fail arguing it is being referenced by other objects + if err := r.Service.DeleteVPC(*vpc.Path); err != nil { + log.Error(err, "failed to delete nsx VPC, would retry exponentially", "NetworkInfo", req.NamespacedName) + deleteFail(r, ctx, obj, &err, r.Client) + return common.ResultRequeueAfter10sec, err + } + if err := r.Service.DeleteIPBlockInVPC(*vpc); err != nil { + log.Error(err, "failed to delete private ip blocks for VPC", "VPC", req.NamespacedName) + return common.ResultRequeueAfter10sec, err + } + } + } + + controllerutil.RemoveFinalizer(obj, commonservice.NetworkInfoFinalizerName) + if err := r.Client.Update(ctx, obj); err != nil { + deleteFail(r, ctx, obj, &err, r.Client) + return common.ResultRequeue, err + } + ncName, err := r.Service.GetNetworkconfigNameFromNS(obj.Namespace) + if err != nil { + log.Error(err, "failed to get network config name for VPC when deleting NetworkInfo CR", "NetworkInfo", obj.Name) + return common.ResultRequeueAfter10sec, err + } + log.V(1).Info("removed finalizer", "NetworkInfo", req.NamespacedName) + deleteVPCNetworkConfigurationStatus(ctx, r.Client, ncName, vpcs, r.Service.ListVPC()) + deleteSuccess(r, ctx, obj) + } else { + // only print a message because it's not a normal case + log.Info("finalizers cannot be recognized", "NetworkInfo", req.NamespacedName) + } + } + return common.ResultNormal, nil +} + +func (r *NetworkInfoReconciler) setupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.NetworkInfo{}). + WithOptions( + controller.Options{ + MaxConcurrentReconciles: common.NumReconcile(), + }). + Watches( + // For created/removed network config, add/remove from vpc network config cache. + // For modified network config, currently only support appending ips to public ip blocks, + // update network config in cache and update nsx vpc object. + &v1alpha1.VPCNetworkConfiguration{}, + &VPCNetworkConfigurationHandler{ + Client: mgr.GetClient(), + vpcService: r.Service, + }, + builder.WithPredicates(VPCNetworkConfigurationPredicate)). + Complete(r) +} + +// Start setup manager and launch GC +func (r *NetworkInfoReconciler) Start(mgr ctrl.Manager) error { + err := r.setupWithManager(mgr) + if err != nil { + return err + } + return nil +} + +// CollectGarbage logic for nsx-vpc is that: +// 1. list all current existing namespace in kubernetes +// 2. list all the nsx-vpc in vpcStore +// 3. loop all the nsx-vpc to get its namespace, check if the namespace still exist +// 4. if ns do not exist anymore, delete the nsx-vpc resource +// it implements the interface GarbageCollector method. +func (r *NetworkInfoReconciler) CollectGarbage(ctx context.Context) { + log.Info("VPC garbage collector started") + // read all nsx-vpc from vpc store + nsxVPCList := r.Service.ListVPC() + if len(nsxVPCList) == 0 { + return + } + + // read all namespaces from k8s + namespaces := &corev1.NamespaceList{} + err := r.Client.List(ctx, namespaces) + if err != nil { + log.Error(err, "failed to list k8s namespaces") + return + } + nsSet := sets.NewString() + for _, ns := range namespaces.Items { + nsSet.Insert(ns.Name) + } + + for i := len(nsxVPCList) - 1; i >= 0; i-- { + nsxVPCNamespace := getNamespaceFromNSXVPC(&nsxVPCList[i]) + if nsSet.Has(nsxVPCNamespace) { + continue + } + elem := nsxVPCList[i] + log.Info("GC collected nsx VPC object", "ID", elem.Id, "Namespace", nsxVPCNamespace) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeNetworkInfo) + err = r.Service.DeleteVPC(*elem.Path) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeNetworkInfo) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeNetworkInfo) + if err := r.Service.DeleteIPBlockInVPC(elem); err != nil { + log.Error(err, "failed to delete private ip blocks for VPC", "VPC", *elem.DisplayName) + } + log.Info("deleted private ip blocks for VPC", "VPC", *elem.DisplayName) + } + } +} diff --git a/pkg/controllers/networkinfo/networkinfo_controller_test.go b/pkg/controllers/networkinfo/networkinfo_controller_test.go new file mode 100644 index 000000000..d2b978daa --- /dev/null +++ b/pkg/controllers/networkinfo/networkinfo_controller_test.go @@ -0,0 +1,594 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package networkinfo + +import ( + "context" + "reflect" + "testing" + + "github.com/agiledragon/gomonkey" + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/config" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx" + + servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" +) + +type fakeVPCConnectivityProfilesClient struct{} + +func (c *fakeVPCConnectivityProfilesClient) Get(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string) (model.VpcConnectivityProfile, error) { + return model.VpcConnectivityProfile{}, nil +} + +func (c *fakeVPCConnectivityProfilesClient) Delete(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string) error { + return nil +} + +func (c *fakeVPCConnectivityProfilesClient) List(orgIdParam string, projectIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.VpcConnectivityProfileListResult, error) { + return model.VpcConnectivityProfileListResult{}, nil +} + +func (c *fakeVPCConnectivityProfilesClient) Patch(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string, vpcConnectivityProfileParam model.VpcConnectivityProfile) error { + return nil +} + +func (c *fakeVPCConnectivityProfilesClient) Update(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string, vpcConnectivityProfileParam model.VpcConnectivityProfile) (model.VpcConnectivityProfile, error) { + return model.VpcConnectivityProfile{}, nil +} + +func createNetworkInfoReconciler() *NetworkInfoReconciler { + service := &vpc.VPCService{ + Service: servicecommon.Service{ + Client: nil, + NSXClient: &nsx.Client{ + VPCConnectivityProfilesClient: &fakeVPCConnectivityProfilesClient{}, + }, + + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + EnforcementPoint: "vmc-enforcementpoint", + UseAVILoadBalancer: false, + }, + }, + }, + VPCNetworkConfigStore: vpc.VPCNetworkInfoStore{ + VPCNetworkConfigMap: map[string]servicecommon.VPCNetworkConfigInfo{}, + }, + VPCNSNetworkConfigStore: vpc.VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: map[string]string{}, + }, + } + + return &NetworkInfoReconciler{ + Client: fake.NewClientBuilder().Build(), + Scheme: fake.NewClientBuilder().Build().Scheme(), + Service: service, + } +} + +func TestNetworkInfoReconciler_Reconcile(t *testing.T) { + type args struct { + req controllerruntime.Request + } + requestArgs := args{ + req: controllerruntime.Request{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: "name"}}, + } + tests := []struct { + name string + prepareFunc func(*testing.T, *NetworkInfoReconciler, context.Context) *gomonkey.Patches + args args + want controllerruntime.Result + wantErr bool + }{ + { + name: "Empty", + prepareFunc: nil, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + { + name: "GatewayConnectionReadyInSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return servicecommon.SystemVPCNetworkConfigurationName, nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return false, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + return &model.Vpc{ + DisplayName: servicecommon.String("vpc-name"), + Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"), + Id: servicecommon.String("vpc-id"), + }, nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ string) (bool, error) { + return false, nil + }) + patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{model.VpcConnectivityProfile{ExternalIpBlocks: []string{"fake-ip-block"}}, nil}, + Times: 1, + }}) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSPath", func(_ *vpc.VPCService, _ string) string { + return "lbs-path" + + }) + patches.ApplyFunc(updateSuccess, + func(_ *NetworkInfoReconciler, _ context.Context, o *v1alpha1.NetworkInfo, _ client.Client, _ *v1alpha1.VPCState, _ string, _ string) { + }) + return patches + + }, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + { + name: "GatewayConnectionReadyInNonSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return servicecommon.SystemVPCNetworkConfigurationName, nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + assert.FailNow(t, "should not be called") + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + return &model.Vpc{ + DisplayName: servicecommon.String("vpc-name"), + Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"), + Id: servicecommon.String("vpc-id"), + }, nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ string) (bool, error) { + return false, nil + }) + patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{model.VpcConnectivityProfile{ExternalIpBlocks: []string{"fake-ip-block"}}, nil}, + Times: 1, + }}) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSPath", func(_ *vpc.VPCService, _ string) string { + return "lbs-path" + + }) + patches.ApplyFunc(updateSuccess, + func(_ *NetworkInfoReconciler, _ context.Context, o *v1alpha1.NetworkInfo, _ client.Client, _ *v1alpha1.VPCState, _ string, _ string) { + }) + return patches + + }, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + { + name: "GatewayConnectionNotReadyInNonSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return "non-system", nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return false, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + assert.FailNow(t, "should not be called") + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + assert.FailNow(t, "should not be called") + return &model.Vpc{}, nil + }) + return patches + + }, + args: requestArgs, + want: common.ResultRequeueAfter60sec, + wantErr: false, + }, + { + name: "AutoSnatEnabledInSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return servicecommon.SystemVPCNetworkConfigurationName, nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return false, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + return &model.Vpc{ + DisplayName: servicecommon.String("vpc-name"), + Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"), + Id: servicecommon.String("vpc-id"), + }, nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ string) (bool, error) { + return false, nil + }) + patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{model.VpcConnectivityProfile{ + ExternalIpBlocks: []string{"fake-ip-block"}, + ServiceGateway: &model.VpcServiceGatewayConfig{ + Enable: servicecommon.Bool(true), + NatConfig: &model.VpcNatConfig{ + EnableDefaultSnat: servicecommon.Bool(true), + }, + }, + }, nil}, + Times: 1, + }}) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSPath", func(_ *vpc.VPCService, _ string) string { + return "lbs-path" + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultSNATIP", func(_ *vpc.VPCService, _ model.Vpc) (string, error) { + return "snat-ip", nil + + }) + patches.ApplyFunc(updateSuccess, + func(_ *NetworkInfoReconciler, _ context.Context, o *v1alpha1.NetworkInfo, _ client.Client, _ *v1alpha1.VPCState, _ string, _ string) { + }) + patches.ApplyFunc(setVPCNetworkConfigurationStatusWithSnatEnabled, + func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) { + if !autoSnatEnabled { + assert.FailNow(t, "should set VPCNetworkConfiguration status with AutoSnatEnabled=true") + } + }) + + return patches + + }, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + { + name: "AutoSnatNotEnabledInSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return servicecommon.SystemVPCNetworkConfigurationName, nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return false, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + return &model.Vpc{ + DisplayName: servicecommon.String("vpc-name"), + Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"), + Id: servicecommon.String("vpc-id"), + }, nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ string) (bool, error) { + return false, nil + }) + patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{model.VpcConnectivityProfile{ + ExternalIpBlocks: []string{"fake-ip-block"}, + ServiceGateway: nil, + }, nil}, + Times: 1, + }}) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSPath", func(_ *vpc.VPCService, _ string) string { + return "lbs-path" + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultSNATIP", func(_ *vpc.VPCService, _ model.Vpc) (string, error) { + return "snat-ip", nil + + }) + patches.ApplyFunc(updateSuccess, + func(_ *NetworkInfoReconciler, _ context.Context, o *v1alpha1.NetworkInfo, _ client.Client, _ *v1alpha1.VPCState, _ string, _ string) { + }) + patches.ApplyFunc(setVPCNetworkConfigurationStatusWithSnatEnabled, + func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) { + if autoSnatEnabled { + assert.FailNow(t, "should set VPCNetworkConfiguration status with AutoSnatEnabled=false") + } + }) + + return patches + + }, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + { + name: "AutoSnatEnabledInNonSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return "non-system", nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + return &model.Vpc{ + DisplayName: servicecommon.String("vpc-name"), + Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"), + Id: servicecommon.String("vpc-id"), + }, nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ string) (bool, error) { + return false, nil + }) + patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{model.VpcConnectivityProfile{ + ExternalIpBlocks: []string{"fake-ip-block"}, + ServiceGateway: &model.VpcServiceGatewayConfig{ + Enable: servicecommon.Bool(true), + NatConfig: &model.VpcNatConfig{ + EnableDefaultSnat: servicecommon.Bool(true), + }, + }, + }, nil}, + Times: 1, + }}) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSPath", func(_ *vpc.VPCService, _ string) string { + return "lbs-path" + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultSNATIP", func(_ *vpc.VPCService, _ model.Vpc) (string, error) { + return "snat-ip", nil + + }) + patches.ApplyFunc(updateSuccess, + func(_ *NetworkInfoReconciler, _ context.Context, o *v1alpha1.NetworkInfo, _ client.Client, _ *v1alpha1.VPCState, _ string, _ string) { + }) + patches.ApplyFunc(setVPCNetworkConfigurationStatusWithSnatEnabled, + func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) { + assert.FailNow(t, "should not be called") + }) + + return patches + + }, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + { + name: "VPCNetworkConfigurationStatusWithNoExternalIPBlockInSystemVPC", + prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) { + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: requestArgs.req.Namespace, + Name: requestArgs.req.Name, + }, + })) + assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "system", + }, + })) + patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ string) (string, error) { + return servicecommon.SystemVPCNetworkConfigurationName, nil + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (servicecommon.VPCNetworkConfigInfo, bool) { + return servicecommon.VPCNetworkConfigInfo{ + VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default", + Org: "default", + NSXProject: "project-quality", + }, true + + }) + patches.ApplyFunc(getGatewayConnectionStatus, func(_ context.Context, _ *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + return false, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateGatewayConnectionStatus", func(_ *vpc.VPCService, _ *servicecommon.VPCNetworkConfigInfo) (bool, string, error) { + return true, "", nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ *v1alpha1.NetworkInfo, _ *servicecommon.VPCNetworkConfigInfo) (*model.Vpc, error) { + return &model.Vpc{ + DisplayName: servicecommon.String("vpc-name"), + Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"), + Id: servicecommon.String("vpc-id"), + }, nil + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ string) (bool, error) { + return false, nil + }) + patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{model.VpcConnectivityProfile{ + ServiceGateway: nil, + }, nil}, + Times: 1, + }}) + patches.ApplyFunc(setVPCNetworkConfigurationStatusWithNoExternalIPBlock, + func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, _ bool) { + t.Log("setVPCNetworkConfigurationStatusWithNoExternalIPBlock") + }) + + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSPath", func(_ *vpc.VPCService, _ string) string { + return "lbs-path" + + }) + patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultSNATIP", func(_ *vpc.VPCService, _ model.Vpc) (string, error) { + return "snat-ip", nil + + }) + patches.ApplyFunc(updateSuccess, + func(_ *NetworkInfoReconciler, _ context.Context, o *v1alpha1.NetworkInfo, _ client.Client, _ *v1alpha1.VPCState, _ string, _ string) { + }) + patches.ApplyFunc(setVPCNetworkConfigurationStatusWithSnatEnabled, + func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) { + if autoSnatEnabled { + assert.FailNow(t, "should set VPCNetworkConfiguration status with AutoSnatEnabled=false") + } + }) + return patches + }, + args: requestArgs, + want: common.ResultNormal, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := createNetworkInfoReconciler() + v1alpha1.AddToScheme(r.Scheme) + ctx := context.TODO() + if tt.prepareFunc != nil { + patches := tt.prepareFunc(t, r, ctx) + defer patches.Reset() + } + got, err := r.Reconcile(ctx, tt.args.req) + if (err != nil) != tt.wantErr { + t.Errorf("Reconcile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Reconcile() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/controllers/networkinfo/networkinfo_utils.go b/pkg/controllers/networkinfo/networkinfo_utils.go new file mode 100644 index 000000000..2a033ed3e --- /dev/null +++ b/pkg/controllers/networkinfo/networkinfo_utils.go @@ -0,0 +1,248 @@ +package networkinfo + +import ( + "context" + "fmt" + "reflect" + "slices" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apitypes "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" + "github.com/vmware-tanzu/nsx-operator/pkg/metrics" + svccommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func deleteFail(r *NetworkInfoReconciler, c context.Context, o *v1alpha1.NetworkInfo, e *error, client client.Client) { + setNetworkInfoVPCStatus(c, o, client, nil) + r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeNetworkInfo) +} + +func updateFail(r *NetworkInfoReconciler, c context.Context, o *v1alpha1.NetworkInfo, e *error, client client.Client, vpcState *v1alpha1.VPCState) { + setNetworkInfoVPCStatus(c, o, client, vpcState) + r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) +} + +func updateSuccess(r *NetworkInfoReconciler, c context.Context, o *v1alpha1.NetworkInfo, client client.Client, + vpcState *v1alpha1.VPCState, ncName string, subnetPath string) { + setNetworkInfoVPCStatus(c, o, client, vpcState) + r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "NetworkInfo CR has been successfully updated") + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, common.MetricResTypeNetworkInfo) +} + +func deleteSuccess(r *NetworkInfoReconciler, c context.Context, o *v1alpha1.NetworkInfo) { + r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "NetworkInfo CR has been successfully deleted") + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeNetworkInfo) +} + +func setNetworkInfoVPCStatus(ctx context.Context, networkInfo *v1alpha1.NetworkInfo, client client.Client, createdVPC *v1alpha1.VPCState) { + // if createdVPC is empty, remove the VPC from networkInfo + if createdVPC == nil { + networkInfo.VPCs = []v1alpha1.VPCState{} + client.Update(ctx, networkInfo) + return + } + existingVPC := &v1alpha1.VPCState{} + if len(networkInfo.VPCs) > 0 { + existingVPC = &networkInfo.VPCs[0] + } + slices.Sort(existingVPC.PrivateIPs) + slices.Sort(createdVPC.PrivateIPs) + if reflect.DeepEqual(*existingVPC, *createdVPC) { + return + } + networkInfo.VPCs = []v1alpha1.VPCState{*createdVPC} + client.Update(ctx, networkInfo) + return +} + +func setVPCNetworkConfigurationStatusWithLBS(ctx context.Context, client client.Client, ncName, vpcName, aviSubnetPath, nsxLBSPath, vpcPath string) { + // read v1alpha1.VPCNetworkConfiguration by ncName + nc := &v1alpha1.VPCNetworkConfiguration{} + err := client.Get(ctx, apitypes.NamespacedName{Name: ncName}, nc) + if err != nil { + log.Error(err, "failed to get VPCNetworkConfiguration", "Name", ncName) + return + } + + // There should only be one vpc info in vpc network config info although it is defined as a list. + // Always update vpcs[0] object + nc.Status.VPCs = []v1alpha1.VPCInfo{{ + Name: vpcName, + AVISESubnetPath: aviSubnetPath, + NSXLoadBalancerPath: nsxLBSPath, + VPCPath: vpcPath, + }} + + if err := client.Status().Update(ctx, nc); err != nil { + log.Error(err, "Update VPCNetworkConfiguration status failed", "ncName", ncName, "vpcName", vpcName, "nc.Status.VPCs", nc.Status.VPCs) + return + } + log.Info("Updated VPCNetworkConfiguration status", "ncName", ncName, "vpcName", vpcName, "nc.Status.VPCs", nc.Status.VPCs) +} + +func setVPCNetworkConfigurationStatusWithGatewayConnection(ctx context.Context, client client.Client, nc *v1alpha1.VPCNetworkConfiguration, gatewayConnectionReady bool, reason string) { + newConditions := []v1alpha1.Condition{ + { + Type: v1alpha1.GatewayConnectionReady, + Status: v1.ConditionFalse, + Reason: reason, + LastTransitionTime: metav1.Time{}, + }, + } + if gatewayConnectionReady { + newConditions[0].Status = v1.ConditionTrue + } + conditionsUpdated := false + for i := range newConditions { + if mergeStatusCondition(ctx, &nc.Status.Conditions, &newConditions[i]) { + conditionsUpdated = true + } + } + if conditionsUpdated { + client.Status().Update(ctx, nc) + log.Info("set VPCNetworkConfiguration status", "ncName", nc.Name, "condition", newConditions[0]) + } +} + +func setVPCNetworkConfigurationStatusWithSnatEnabled(ctx context.Context, client client.Client, nc *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) { + newConditions := []v1alpha1.Condition{ + { + Type: v1alpha1.AutoSnatEnabled, + Status: v1.ConditionFalse, + LastTransitionTime: metav1.Time{}, + }, + } + if autoSnatEnabled { + newConditions[0].Status = v1.ConditionTrue + } + conditionsUpdated := false + for i := range newConditions { + if mergeStatusCondition(ctx, &nc.Status.Conditions, &newConditions[i]) { + conditionsUpdated = true + } + } + if conditionsUpdated { + client.Status().Update(ctx, nc) + } +} + +func setVPCNetworkConfigurationStatusWithNoExternalIPBlock(ctx context.Context, client client.Client, nc *v1alpha1.VPCNetworkConfiguration, hasExternalIPs bool) { + newCondition := v1alpha1.Condition{ + Type: v1alpha1.ExternalIPBlocksConfigured, + LastTransitionTime: metav1.Time{}, + } + if !hasExternalIPs { + newCondition.Status = v1.ConditionFalse + newCondition.Reason = svccommon.ReasonNoExternalIPBlocksInVPCConnectivityProfile + newCondition.Message = "No External IP Blocks exist in VPC Connectivity Profile" + } else { + newCondition.Status = v1.ConditionTrue + } + if mergeStatusCondition(ctx, &nc.Status.Conditions, &newCondition) { + if err := client.Status().Update(ctx, nc); err != nil { + log.Error(err, "update VPCNetworkConfiguration status failed", "VPCNetworkConfiguration", nc.Name) + return + } + } + log.Info("Updated VPCNetworkConfiguration status", "VPCNetworkConfiguration", nc.Name, "status", newCondition) +} + +// TODO: abstract the logic of merging condition for common, which can be used by the other controller, e.g. security policy +func mergeStatusCondition(ctx context.Context, conditions *[]v1alpha1.Condition, newCondition *v1alpha1.Condition) bool { + existingCondition := getExistingConditionOfType(newCondition.Type, *conditions) + if existingCondition != nil { + // Don't compare the timestamp. + existingCondition.LastTransitionTime = metav1.Time{} + } + + if reflect.DeepEqual(existingCondition, newCondition) { + log.V(2).Info("conditions already match", "New Condition", newCondition, "Existing Condition", existingCondition) + return false + } + + if existingCondition != nil { + existingCondition.Reason = newCondition.Reason + existingCondition.Message = newCondition.Message + existingCondition.Status = newCondition.Status + existingCondition.LastTransitionTime = metav1.Now() + } else { + newCondition.LastTransitionTime = metav1.Now() + *conditions = append(*conditions, *newCondition) + } + return true +} + +func getExistingConditionOfType(conditionType v1alpha1.ConditionType, existingConditions []v1alpha1.Condition) *v1alpha1.Condition { + for i := range existingConditions { + if existingConditions[i].Type == conditionType { + return &existingConditions[i] + } + } + return nil +} + +func getGatewayConnectionStatus(ctx context.Context, nc *v1alpha1.VPCNetworkConfiguration) (bool, string, error) { + gatewayConnectionReady := false + reason := "" + for _, condition := range nc.Status.Conditions { + if condition.Type != v1alpha1.GatewayConnectionReady { + continue + } + if condition.Status == v1.ConditionTrue { + gatewayConnectionReady = true + reason = condition.Reason + break + } + } + return gatewayConnectionReady, reason, nil +} + +func deleteVPCNetworkConfigurationStatus(ctx context.Context, client client.Client, ncName string, staleVPCs []*model.Vpc, aliveVPCs []model.Vpc) { + aliveVPCNames := sets.New[string]() + for _, vpcModel := range aliveVPCs { + aliveVPCNames.Insert(*vpcModel.DisplayName) + } + staleVPCNames := sets.New[string]() + for _, vpc := range staleVPCs { + staleVPCNames.Insert(*vpc.DisplayName) + } + // read v1alpha1.VPCNetworkConfiguration by ncName + nc := &v1alpha1.VPCNetworkConfiguration{} + err := client.Get(ctx, apitypes.NamespacedName{Name: ncName}, nc) + if err != nil { + log.Error(err, "failed to get VPCNetworkConfiguration", "Name", ncName) + return + } + // iterate through VPCNetworkConfiguration.Status.VPCs, if vpcName does not exist in the staleVPCNames, append in new VPCs status + var newVPCInfos []v1alpha1.VPCInfo + for _, vpc := range nc.Status.VPCs { + if !staleVPCNames.Has(vpc.Name) && aliveVPCNames.Has(vpc.Name) { + newVPCInfos = append(newVPCInfos, vpc) + } + } + nc.Status.VPCs = newVPCInfos + if err := client.Status().Update(ctx, nc); err != nil { + log.Error(err, "failed to delete stale VPCNetworkConfiguration status", "Name", ncName, "nc.Status.VPCs", nc.Status.VPCs, "staleVPCs", staleVPCNames) + return + } + log.Info("Deleted stale VPCNetworkConfiguration status", "Name", ncName, "nc.Status.VPCs", nc.Status.VPCs, "staleVPCs", staleVPCNames) +} + +func getNamespaceFromNSXVPC(nsxVPC *model.Vpc) string { + tags := nsxVPC.Tags + for _, tag := range tags { + if *tag.Scope == svccommon.TagScopeNamespace { + return *tag.Tag + } + } + return "" +} diff --git a/pkg/controllers/networkinfo/networkinfo_utils_test.go b/pkg/controllers/networkinfo/networkinfo_utils_test.go new file mode 100644 index 000000000..b10edf119 --- /dev/null +++ b/pkg/controllers/networkinfo/networkinfo_utils_test.go @@ -0,0 +1,202 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package networkinfo + +import ( + "context" + "testing" + + "github.com/agiledragon/gomonkey" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" +) + +func TestSetVPCNetworkConfigurationStatusWithGatewayConnection(t *testing.T) { + tests := []struct { + name string + prepareFunc func(*testing.T, context.Context, client.Client, string, bool, string, *v1alpha1.VPCNetworkConfiguration) *gomonkey.Patches + gatewayConnectionReady bool + reason string + expectedConditionType v1alpha1.ConditionType + expectedConditionStatus corev1.ConditionStatus + expectedConditionReason string + }{ + { + name: "GatewayConnectionReady", + prepareFunc: func(_ *testing.T, ctx context.Context, client client.Client, _ string, _ bool, _ string, nc *v1alpha1.VPCNetworkConfiguration) (patches *gomonkey.Patches) { + assert.NoError(t, client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + })) + patches = &gomonkey.Patches{} + return patches + }, + gatewayConnectionReady: true, + reason: "", + expectedConditionType: v1alpha1.GatewayConnectionReady, + expectedConditionStatus: corev1.ConditionTrue, + expectedConditionReason: "", + }, + { + name: "GatewayConnectionNotReady", + prepareFunc: func(_ *testing.T, ctx context.Context, client client.Client, _ string, _ bool, _ string, nc *v1alpha1.VPCNetworkConfiguration) (patches *gomonkey.Patches) { + assert.NoError(t, client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + })) + patches = &gomonkey.Patches{} + return patches + }, + gatewayConnectionReady: false, + reason: "EdgeMissingInProject", + expectedConditionType: v1alpha1.GatewayConnectionReady, + expectedConditionStatus: corev1.ConditionFalse, + expectedConditionReason: "EdgeMissingInProject", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.TODO() + scheme := clientgoscheme.Scheme + v1alpha1.AddToScheme(scheme) + client := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&v1alpha1.VPCNetworkConfiguration{}).Build() + actualCR := &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + } + if tt.prepareFunc != nil { + patches := tt.prepareFunc(t, ctx, client, "ncName", tt.gatewayConnectionReady, tt.reason, actualCR) + defer patches.Reset() + } + setVPCNetworkConfigurationStatusWithGatewayConnection(ctx, client, actualCR, tt.gatewayConnectionReady, tt.reason) + assert.Equal(t, tt.expectedConditionReason, actualCR.Status.Conditions[0].Reason) + assert.Equal(t, tt.expectedConditionType, actualCR.Status.Conditions[0].Type) + assert.Equal(t, tt.expectedConditionStatus, actualCR.Status.Conditions[0].Status) + }) + } +} + +func TestSetVPCNetworkConfigurationStatusWithSnatEnabled(t *testing.T) { + tests := []struct { + name string + prepareFunc func(*testing.T, context.Context, client.Client, string, bool, *v1alpha1.VPCNetworkConfiguration) *gomonkey.Patches + autoSnatEnabled bool + expectedConditionType v1alpha1.ConditionType + expectedConditionStatus corev1.ConditionStatus + expectedConditionReason string + }{ + { + name: "AutoSnatEnabled", + prepareFunc: func(_ *testing.T, ctx context.Context, client client.Client, _ string, _ bool, nc *v1alpha1.VPCNetworkConfiguration) (patches *gomonkey.Patches) { + assert.NoError(t, client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + })) + patches = &gomonkey.Patches{} + return patches + }, + autoSnatEnabled: true, + expectedConditionType: v1alpha1.AutoSnatEnabled, + expectedConditionStatus: corev1.ConditionTrue, + expectedConditionReason: "", + }, + { + name: "AutoSnatDisabled", + prepareFunc: func(_ *testing.T, ctx context.Context, client client.Client, _ string, _ bool, nc *v1alpha1.VPCNetworkConfiguration) (patches *gomonkey.Patches) { + assert.NoError(t, client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + })) + patches = &gomonkey.Patches{} + return patches + }, + autoSnatEnabled: false, + expectedConditionType: v1alpha1.AutoSnatEnabled, + expectedConditionStatus: corev1.ConditionFalse, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.TODO() + scheme := clientgoscheme.Scheme + v1alpha1.AddToScheme(scheme) + client := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&v1alpha1.VPCNetworkConfiguration{}).Build() + actualCR := &v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + } + if tt.prepareFunc != nil { + patches := tt.prepareFunc(t, ctx, client, "ncName", tt.autoSnatEnabled, actualCR) + defer patches.Reset() + } + setVPCNetworkConfigurationStatusWithSnatEnabled(ctx, client, actualCR, tt.autoSnatEnabled) + assert.Equal(t, tt.expectedConditionType, actualCR.Status.Conditions[0].Type) + assert.Equal(t, tt.expectedConditionStatus, actualCR.Status.Conditions[0].Status) + }) + } +} + +func TestGetGatewayConnectionStatus(t *testing.T) { + tests := []struct { + name string + prepareFunc func(*testing.T, context.Context, client.Client) *gomonkey.Patches + conditions []v1alpha1.Condition + expectedStatus bool + expectedReason string + }{ + { + name: "EmptyCondition", + prepareFunc: nil, + conditions: []v1alpha1.Condition{}, + expectedStatus: false, + expectedReason: "", + }, + { + name: "GetGatewayConnectionStatusReady", + prepareFunc: nil, + conditions: []v1alpha1.Condition{ + { + Type: v1alpha1.AutoSnatEnabled, + Status: corev1.ConditionFalse, + }, + { + Type: v1alpha1.GatewayConnectionReady, + Status: corev1.ConditionTrue, + Reason: "reason", + }, + }, + expectedStatus: true, + expectedReason: "reason", + }, + } + for _, tt := range tests { + ctx := context.TODO() + t.Run(tt.name, func(t *testing.T) { + vpcNetworkConfiguration := v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ncName", + }, + Status: v1alpha1.VPCNetworkConfigurationStatus{ + Conditions: tt.conditions, + }, + } + gatewayConnectionReady, reason, _ := getGatewayConnectionStatus(ctx, &vpcNetworkConfiguration) + assert.Equal(t, tt.expectedReason, reason) + assert.Equal(t, tt.expectedStatus, gatewayConnectionReady) + }) + } +} diff --git a/pkg/controllers/vpc/vpcnetworkconfig_handler.go b/pkg/controllers/networkinfo/vpcnetworkconfig_handler.go similarity index 53% rename from pkg/controllers/vpc/vpcnetworkconfig_handler.go rename to pkg/controllers/networkinfo/vpcnetworkconfig_handler.go index b7839b780..d17a39d8c 100644 --- a/pkg/controllers/vpc/vpcnetworkconfig_handler.go +++ b/pkg/controllers/networkinfo/vpcnetworkconfig_handler.go @@ -1,13 +1,17 @@ -package vpc +package networkinfo import ( "context" + "errors" + "strconv" + "strings" "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + + commontypes "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/workqueue" @@ -22,7 +26,7 @@ import ( type VPCNetworkConfigurationHandler struct { Client client.Client - vpcService *vpc.VPCService + vpcService commontypes.VPCServiceProvider } func (h *VPCNetworkConfigurationHandler) Create(_ context.Context, e event.CreateEvent, _ workqueue.RateLimitingInterface) { @@ -46,17 +50,10 @@ func (h *VPCNetworkConfigurationHandler) Generic(_ context.Context, _ event.Gene log.V(1).Info("VPCNetworkConfiguration generic event, do nothing") } -func (h *VPCNetworkConfigurationHandler) Update(_ context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) { +func (h *VPCNetworkConfigurationHandler) Update(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) { log.V(1).Info("start processing VPC network config update event") - oldNc := e.ObjectOld.(*v1alpha1.VPCNetworkConfiguration) newNc := e.ObjectNew.(*v1alpha1.VPCNetworkConfiguration) - if getListSize(oldNc.Spec.ExternalIPv4Blocks) == getListSize(newNc.Spec.ExternalIPv4Blocks) && - getListSize(oldNc.Spec.PrivateIPv4CIDRs) == getListSize(newNc.Spec.PrivateIPv4CIDRs) { - log.V(1).Info("only support updating external/private ipv4 cidr, no change") - return - } - // update network config info in store info, err := buildNetworkConfigInfo(*newNc) if err != nil { @@ -66,22 +63,20 @@ func (h *VPCNetworkConfigurationHandler) Update(_ context.Context, e event.Updat h.vpcService.RegisterVPCNetworkConfig(newNc.Name, *info) nss := h.vpcService.GetNamespacesByNetworkconfigName(newNc.Name) - ctx := context.Background() - // find vpcs under each ns, and reconcile the vpc object for _, ns := range nss { - vpcList := &v1alpha1.VPCList{} - err := h.Client.List(ctx, vpcList, client.InNamespace(ns)) + networkInfos := &v1alpha1.NetworkInfoList{} + err := h.Client.List(ctx, networkInfos, client.InNamespace(ns)) if err != nil { log.Error(err, "failed to list VPCs in namespace", "Namespace", ns) continue } - for _, vpc := range vpcList.Items { - log.Info("reconcile VPC CR due to modifying network config CR", "VPC", vpc.Name, "Namespace", ns, "NetworkConfig", newNc.Name) + for _, networkInfo := range networkInfos.Items { + log.Info("reconcile NetworkInfo CR due to modifying network config CR", "NetworkInfo", networkInfo.Name, "Namespace", ns, "NetworkConfig", newNc.Name) q.Add(reconcile.Request{ NamespacedName: types.NamespacedName{ - Name: vpc.Name, - Namespace: vpc.Namespace, + Name: networkInfo.Name, + Namespace: networkInfo.Namespace, }, }) } @@ -103,10 +98,46 @@ var VPCNetworkConfigurationPredicate = predicate.Funcs{ }, } -func getListSize(s []string) int { - if s == nil { - return 0 - } else { - return len(s) +func buildNetworkConfigInfo(vpcConfigCR v1alpha1.VPCNetworkConfiguration) (*commontypes.VPCNetworkConfigInfo, error) { + org, project, err := nsxtProjectPathToId(vpcConfigCR.Spec.NSXProject) + if err != nil { + log.Error(err, "failed to parse NSX project in network config", "Project Path", vpcConfigCR.Spec.NSXProject) + return nil, err + } + + ninfo := &commontypes.VPCNetworkConfigInfo{ + IsDefault: isDefaultNetworkConfigCR(vpcConfigCR), + Org: org, + Name: vpcConfigCR.Name, + VPCConnectivityProfile: vpcConfigCR.Spec.VPCConnectivityProfile, + NSXProject: project, + PrivateIPs: vpcConfigCR.Spec.PrivateIPs, + DefaultSubnetSize: vpcConfigCR.Spec.DefaultSubnetSize, + VPCPath: vpcConfigCR.Spec.VPC, + } + return ninfo, nil +} + +func isDefaultNetworkConfigCR(vpcConfigCR v1alpha1.VPCNetworkConfiguration) bool { + annos := vpcConfigCR.GetAnnotations() + val, exist := annos[commontypes.AnnotationDefaultNetworkConfig] + if exist { + boolVar, err := strconv.ParseBool(val) + if err != nil { + log.Error(err, "failed to parse annotation to check default NetworkConfig", "Annotation", annos[commontypes.AnnotationDefaultNetworkConfig]) + return false + } + return boolVar + } + return false +} + +// parse org id and project id from nsxProject path +// example /orgs/default/projects/nsx_operator_e2e_test +func nsxtProjectPathToId(path string) (string, string, error) { + parts := strings.Split(path, "/") + if len(parts) < 4 { + return "", "", errors.New("invalid NSXT project path") } + return parts[2], parts[len(parts)-1], nil } diff --git a/pkg/controllers/vpc/vpc_utils_test.go b/pkg/controllers/networkinfo/vpcnetworkconfig_handler_test.go similarity index 56% rename from pkg/controllers/vpc/vpc_utils_test.go rename to pkg/controllers/networkinfo/vpcnetworkconfig_handler_test.go index 6ee365c23..fffe95733 100644 --- a/pkg/controllers/vpc/vpc_utils_test.go +++ b/pkg/controllers/networkinfo/vpcnetworkconfig_handler_test.go @@ -1,14 +1,13 @@ -package vpc +package networkinfo import ( "testing" + "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" types "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - - "github.com/stretchr/testify/assert" ) func TestNsxtProjectPathToId(t *testing.T) { @@ -65,7 +64,7 @@ func TestBuildNetworkConfigInfo(t *testing.T) { emptyCRD := &v1alpha1.VPCNetworkConfiguration{} emptyCRD2 := &v1alpha1.VPCNetworkConfiguration{ Spec: v1alpha1.VPCNetworkConfigurationSpec{ - NSXTProject: "/invalid/path", + NSXProject: "/invalid/path", }, } _, e := buildNetworkConfigInfo(*emptyCRD) @@ -74,22 +73,20 @@ func TestBuildNetworkConfigInfo(t *testing.T) { assert.NotNil(t, e) spec1 := v1alpha1.VPCNetworkConfigurationSpec{ - DefaultGatewayPath: "test-gw-path-1", - EdgeClusterPath: "test-edge-path-1", - ExternalIPv4Blocks: []string{"external-ipb-1", "external-ipb-2"}, - PrivateIPv4CIDRs: []string{"private-ipb-1", "private-ipb-2"}, - DefaultIPv4SubnetSize: 64, - DefaultSubnetAccessMode: "Public", - NSXTProject: "/orgs/default/projects/nsx_operator_e2e_test", + PrivateIPs: []string{"private-ipb-1", "private-ipb-2"}, + DefaultSubnetSize: 64, + VPCConnectivityProfile: "test-VPCConnectivityProfile", + NSXProject: "/orgs/default/projects/nsx_operator_e2e_test", } spec2 := v1alpha1.VPCNetworkConfigurationSpec{ - DefaultGatewayPath: "test-gw-path-2", - EdgeClusterPath: "test-edge-path-2", - ExternalIPv4Blocks: []string{"external-ipb-1", "external-ipb-2"}, - PrivateIPv4CIDRs: []string{"private-ipb-1", "private-ipb-2"}, - DefaultIPv4SubnetSize: 32, - DefaultSubnetAccessMode: "Private", - NSXTProject: "/orgs/anotherOrg/projects/anotherProject", + PrivateIPs: []string{"private-ipb-1", "private-ipb-2"}, + DefaultSubnetSize: 32, + NSXProject: "/orgs/anotherOrg/projects/anotherProject", + } + spec3 := v1alpha1.VPCNetworkConfigurationSpec{ + DefaultSubnetSize: 28, + NSXProject: "/orgs/anotherOrg/projects/anotherProject", + VPC: "vpc33", } testCRD1 := v1alpha1.VPCNetworkConfiguration{ Spec: spec1, @@ -110,33 +107,43 @@ func TestBuildNetworkConfigInfo(t *testing.T) { } testCRD3.Name = "test-3" + testCRD4 := v1alpha1.VPCNetworkConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + types.AnnotationDefaultNetworkConfig: "false", + }, + }, + Spec: spec3, + } + testCRD3.Name = "test-4" + tests := []struct { - name string - nc v1alpha1.VPCNetworkConfiguration - gw string - edge string - org string - project string - subnetSize int - accessMode string - isDefault bool + name string + nc v1alpha1.VPCNetworkConfiguration + gw string + edge string + org string + project string + subnetSize int + accessMode string + isDefault bool + vpcConnectivityProfile string + vpcPath string }{ - {"1", testCRD1, "test-gw-path-1", "test-edge-path-1", "default", "nsx_operator_e2e_test", 64, "Public", false}, - {"2", testCRD2, "test-gw-path-2", "test-edge-path-2", "anotherOrg", "anotherProject", 32, "Private", false}, - {"3", testCRD3, "test-gw-path-2", "test-edge-path-2", "anotherOrg", "anotherProject", 32, "Private", true}, + {"test-nsxtProjectPathToId", testCRD1, "test-gw-path-1", "test-edge-path-1", "default", "nsx_operator_e2e_test", 64, "Public", false, "", ""}, + {"with-VPCConnectivityProfile", testCRD2, "test-gw-path-2", "test-edge-path-2", "anotherOrg", "anotherProject", 32, "Private", false, "test-VPCConnectivityProfile", ""}, + {"with-defaultNetworkConfig", testCRD3, "test-gw-path-2", "test-edge-path-2", "anotherOrg", "anotherProject", 32, "Private", true, "", ""}, + {"with-preCreatedVPC", testCRD4, "", "", "anotherOrg", "anotherProject", 28, "Private", false, "", "vpc33"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { nc, e := buildNetworkConfigInfo(tt.nc) assert.Nil(t, e) - assert.Equal(t, tt.gw, nc.DefaultGatewayPath) - assert.Equal(t, tt.edge, nc.EdgeClusterPath) assert.Equal(t, tt.org, nc.Org) - assert.Equal(t, tt.project, nc.NsxtProject) - assert.Equal(t, tt.subnetSize, nc.DefaultIPv4SubnetSize) - assert.Equal(t, tt.accessMode, nc.DefaultSubnetAccessMode) + assert.Equal(t, tt.project, nc.NSXProject) + assert.Equal(t, tt.subnetSize, nc.DefaultSubnetSize) assert.Equal(t, tt.isDefault, nc.IsDefault) + assert.Equal(t, tt.vpcPath, nc.VPCPath) }) } - } diff --git a/pkg/controllers/networkpolicy/networkpolicy_controller.go b/pkg/controllers/networkpolicy/networkpolicy_controller.go index 75cb4a294..f4d840e2b 100644 --- a/pkg/controllers/networkpolicy/networkpolicy_controller.go +++ b/pkg/controllers/networkpolicy/networkpolicy_controller.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "os" - "time" v1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" @@ -31,7 +30,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins @@ -46,22 +45,22 @@ type NetworkPolicyReconciler struct { Recorder record.EventRecorder } -func updateFail(r *NetworkPolicyReconciler, c *context.Context, o *networkingv1.NetworkPolicy, e *error) { +func updateFail(r *NetworkPolicyReconciler, c context.Context, o *networkingv1.NetworkPolicy, e *error) { r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) } -func deleteFail(r *NetworkPolicyReconciler, c *context.Context, o *networkingv1.NetworkPolicy, e *error) { +func deleteFail(r *NetworkPolicyReconciler, c context.Context, o *networkingv1.NetworkPolicy, e *error) { r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) } -func updateSuccess(r *NetworkPolicyReconciler, c *context.Context, o *networkingv1.NetworkPolicy) { +func updateSuccess(r *NetworkPolicyReconciler, c context.Context, o *networkingv1.NetworkPolicy) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "NetworkPolicy has been successfully updated") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) } -func deleteSuccess(r *NetworkPolicyReconciler, _ *context.Context, o *networkingv1.NetworkPolicy) { +func deleteSuccess(r *NetworkPolicyReconciler, _ context.Context, o *networkingv1.NetworkPolicy) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "NetworkPolicy has been successfully deleted") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } @@ -82,7 +81,7 @@ func (r *NetworkPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reques controllerutil.AddFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) if err := r.Client.Update(ctx, networkPolicy); err != nil { log.Error(err, "add finalizer", "networkpolicy", req.NamespacedName) - updateFail(r, &ctx, networkPolicy, &err) + updateFail(r, ctx, networkPolicy, &err) return ResultRequeue, err } log.V(1).Info("added finalizer on networkpolicy", "networkpolicy", req.NamespacedName) @@ -91,30 +90,30 @@ func (r *NetworkPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reques if err := r.Service.CreateOrUpdateSecurityPolicy(networkPolicy); err != nil { if errors.As(err, &nsxutil.RestrictionError{}) { log.Error(err, err.Error(), "networkpolicy", req.NamespacedName) - updateFail(r, &ctx, networkPolicy, &err) + updateFail(r, ctx, networkPolicy, &err) return ResultNormal, nil } log.Error(err, "create or update failed, would retry exponentially", "networkpolicy", req.NamespacedName) - updateFail(r, &ctx, networkPolicy, &err) + updateFail(r, ctx, networkPolicy, &err) return ResultRequeue, err } - updateSuccess(r, &ctx, networkPolicy) + updateSuccess(r, ctx, networkPolicy) } else { if controllerutil.ContainsFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) if err := r.Service.DeleteSecurityPolicy(networkPolicy, false, servicecommon.ResourceTypeNetworkPolicy); err != nil { log.Error(err, "deletion failed, would retry exponentially", "networkpolicy", req.NamespacedName) - deleteFail(r, &ctx, networkPolicy, &err) + deleteFail(r, ctx, networkPolicy, &err) return ResultRequeue, err } controllerutil.RemoveFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) if err := r.Client.Update(ctx, networkPolicy); err != nil { log.Error(err, "deletion failed, would retry exponentially", "networkpolicy", req.NamespacedName) - deleteFail(r, &ctx, networkPolicy, &err) + deleteFail(r, ctx, networkPolicy, &err) return ResultRequeue, err } log.V(1).Info("removed finalizer", "networkpolicy", req.NamespacedName) - deleteSuccess(r, &ctx, networkPolicy) + deleteSuccess(r, ctx, networkPolicy) } else { // only print a message because it's not a normal case log.Info("finalizers cannot be recognized", "networkpolicy", req.NamespacedName) @@ -140,51 +139,39 @@ func (r *NetworkPolicyReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } -// GarbageCollector collect networkpolicy which has been removed from K8s. -// cancel is used to break the loop during UT -func (r *NetworkPolicyReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxPolicySet := r.Service.ListNetworkPolicyID() - if len(nsxPolicySet) == 0 { - continue - } - policyList := &networkingv1.NetworkPolicyList{} - err := r.Client.List(ctx, policyList) - if err != nil { - log.Error(err, "failed to list NetworkPolicy") - continue - } +// CollectGarbage collect networkpolicy which has been removed from K8s. +// it implements the interface GarbageCollector method. +func (r *NetworkPolicyReconciler) CollectGarbage(ctx context.Context) { + log.Info("networkpolicy garbage collector started") + nsxPolicySet := r.Service.ListNetworkPolicyID() + if len(nsxPolicySet) == 0 { + return + } + policyList := &networkingv1.NetworkPolicyList{} + err := r.Client.List(ctx, policyList) + if err != nil { + log.Error(err, "failed to list NetworkPolicy") + return + } - CRPolicySet := sets.NewString() - for _, policy := range policyList.Items { - CRPolicySet.Insert(r.Service.BuildNetworkPolicyAllowPolicyID(string(policy.UID))) - CRPolicySet.Insert(r.Service.BuildNetworkPolicyIsolationPolicyID(string(policy.UID))) - } + CRPolicySet := sets.New[string]() + for _, policy := range policyList.Items { + CRPolicySet.Insert(r.Service.BuildNetworkPolicyAllowPolicyID(string(policy.UID))) + CRPolicySet.Insert(r.Service.BuildNetworkPolicyIsolationPolicyID(string(policy.UID))) + } - for elem := range nsxPolicySet { - if CRPolicySet.Has(elem) { - continue - } - log.V(1).Info("GC collected NetworkPolicy", "ID", elem) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) - err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeNetworkPolicy) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) - } + diffSet := nsxPolicySet.Difference(CRPolicySet) + for elem := range diffSet { + log.V(1).Info("GC collected NetworkPolicy", "ID", elem) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) + err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeNetworkPolicy) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } } } @@ -200,4 +187,5 @@ func StartNetworkPolicyController(mgr ctrl.Manager, commonService servicecommon. log.Error(err, "failed to create controller", "controller", "NetworkPolicy") os.Exit(1) } + go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, networkPolicyReconcile.CollectGarbage) } diff --git a/pkg/controllers/node/node_controller.go b/pkg/controllers/node/node_controller.go index ef2e71f2f..e1b25a7fd 100644 --- a/pkg/controllers/node/node_controller.go +++ b/pkg/controllers/node/node_controller.go @@ -6,12 +6,15 @@ package node import ( "context" "os" + "reflect" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" apimachineryruntime "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -20,7 +23,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log MetricResTypeNode = common.MetricResTypeNode ) @@ -68,6 +71,7 @@ func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. func (r *NodeReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&v1.Node{}). + WithEventFilter(PredicateFuncsNode). Complete(r) } @@ -92,3 +96,36 @@ func (r *NodeReconciler) Start(mgr ctrl.Manager) error { } return nil } + +// PredicateFuncsNode filters out events where only resourceVersion, lastHeartbeatTime, or lastTransitionTime have changed +var PredicateFuncsNode = predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldNode, okOld := e.ObjectOld.(*v1.Node) + newNode, okNew := e.ObjectNew.(*v1.Node) + if !okOld || !okNew { + return true + } + + // If only the heartbeat time, transition time and resource version has changed, and other properties unchanged, ignore the update + if len(newNode.Status.Conditions) > 0 && len(oldNode.Status.Conditions) > 0 { + if newNode.ResourceVersion != oldNode.ResourceVersion && + newNode.Status.Conditions[0].LastHeartbeatTime != oldNode.Status.Conditions[0].LastHeartbeatTime && + newNode.Status.Conditions[0].LastTransitionTime != oldNode.Status.Conditions[0].LastTransitionTime { + oldNode.Status.Conditions[0].LastHeartbeatTime = newNode.Status.Conditions[0].LastHeartbeatTime + oldNode.Status.Conditions[0].LastTransitionTime = newNode.Status.Conditions[0].LastTransitionTime + return !reflect.DeepEqual(oldNode.Status, newNode.Status) + } + } + return true + + }, + CreateFunc: func(e event.CreateEvent) bool { + return true + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return true + }, + GenericFunc: func(e event.GenericEvent) bool { + return true + }, +} diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go index d35cf5c7e..3d78d2efa 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go @@ -7,7 +7,6 @@ import ( "context" "errors" "fmt" - "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -22,7 +21,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -33,11 +32,13 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins MetricResType = common.MetricResTypeNSXServiceAccount + count = uint16(0) + ca []byte ) // NSXServiceAccountReconciler reconciles a NSXServiceAccount object. @@ -78,7 +79,7 @@ func (r *NSXServiceAccountReconciler) Reconcile(ctx context.Context, req ctrl.Re // So need to check NSX version before starting NSXServiceAccount reconcile if !r.Service.NSXClient.NSXCheckVersion(nsx.ServiceAccount) { err := errors.New("NSX version check failed, NSXServiceAccount feature is not supported") - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, obj, &err) // if NSX version check fails, it will be put back to reconcile queue and be reconciled after 5 minutes return ResultRequeueAfter5mins, nil } @@ -89,7 +90,7 @@ func (r *NSXServiceAccountReconciler) Reconcile(ctx context.Context, req ctrl.Re controllerutil.AddFinalizer(obj, servicecommon.NSXServiceAccountFinalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "add finalizer", "nsxserviceaccount", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, obj, &err) return ResultRequeue, err } log.V(1).Info("added finalizer on CR", "nsxserviceaccount", req.NamespacedName) @@ -108,10 +109,10 @@ func (r *NSXServiceAccountReconciler) Reconcile(ctx context.Context, req ctrl.Re } if err := r.Service.CreateOrUpdateNSXServiceAccount(ctx, obj); err != nil { log.Error(err, "operate failed, would retry exponentially", "nsxserviceaccount", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, obj, &err) return ResultRequeue, err } - updateSuccess(r, &ctx, obj) + updateSuccess(r, ctx, obj) } else { if controllerutil.ContainsFinalizer(obj, servicecommon.NSXServiceAccountFinalizerName) { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) @@ -120,17 +121,17 @@ func (r *NSXServiceAccountReconciler) Reconcile(ctx context.Context, req ctrl.Re Name: obj.Name, }, obj.UID); err != nil { log.Error(err, "deleting failed, would retry exponentially", "nsxserviceaccount", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) + deleteFail(r, ctx, obj, &err) return ResultRequeue, err } controllerutil.RemoveFinalizer(obj, servicecommon.NSXServiceAccountFinalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "removing finalizer failed, would retry exponentially", "nsxserviceaccount", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) + deleteFail(r, ctx, obj, &err) return ResultRequeue, err } log.V(1).Info("removed finalizer", "nsxserviceaccount", req.NamespacedName) - deleteSuccess(r, &ctx, obj) + deleteSuccess(r, ctx, obj) } else { // only print a message because it's not a normal case log.Info("finalizers cannot be recognized", "nsxserviceaccount", req.NamespacedName) @@ -163,41 +164,29 @@ func (r *NSXServiceAccountReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } -// GarbageCollector collect NSXServiceAccount which has been removed from crd. -// cancel is used to break the loop during UT -func (r *NSXServiceAccountReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - count := uint16(0) - ca := r.Service.NSXConfig.GetCACert() - log.Info("garbage collector started") - for { - nsxServiceAccountList := &nsxvmwarecomv1alpha1.NSXServiceAccountList{} - var gcSuccessCount, gcErrorCount uint32 - var err error - nsxServiceAccountUIDSet := r.Service.ListNSXServiceAccountRealization() - if len(nsxServiceAccountUIDSet) == 0 { - goto gcWait - } - err = r.Client.List(ctx, nsxServiceAccountList) - if err != nil { - log.Error(err, "failed to list NSXServiceAccount CR") - goto gcWait - } - gcSuccessCount, gcErrorCount = r.garbageCollector(nsxServiceAccountUIDSet, nsxServiceAccountList) - log.V(1).Info("gc collects NSXServiceAccount CR", "success", gcSuccessCount, "error", gcErrorCount) - count, ca = r.validateRealized(count, ca, nsxServiceAccountList) - gcWait: - select { - case <-cancel: - return - case <-time.After(timeout): - } +// CollectGarbage collect NSXServiceAccount which has been removed from crd. +// it implements the interface GarbageCollector method. +func (r *NSXServiceAccountReconciler) CollectGarbage(ctx context.Context) { + log.Info("nsx service account garbage collector started") + ca = r.Service.NSXConfig.GetCACert() + nsxServiceAccountList := &nsxvmwarecomv1alpha1.NSXServiceAccountList{} + var gcSuccessCount, gcErrorCount uint32 + var err error + nsxServiceAccountUIDSet := r.Service.ListNSXServiceAccountRealization() + if len(nsxServiceAccountUIDSet) == 0 { + return + } + err = r.Client.List(ctx, nsxServiceAccountList) + if err != nil { + log.Error(err, "failed to list NSXServiceAccount CR") + return } + gcSuccessCount, gcErrorCount = r.garbageCollector(nsxServiceAccountUIDSet, nsxServiceAccountList) + log.V(1).Info("gc collects NSXServiceAccount CR", "success", gcSuccessCount, "error", gcErrorCount) + count, ca = r.validateRealized(count, ca, nsxServiceAccountList) } func (r *NSXServiceAccountReconciler) validateRealized(count uint16, ca []byte, nsxServiceAccountList *nsxvmwarecomv1alpha1.NSXServiceAccountList) (uint16, []byte) { @@ -253,7 +242,7 @@ func (r *NSXServiceAccountReconciler) garbageCollector(nsxServiceAccountUIDSet s return } -func (r *NSXServiceAccountReconciler) updateNSXServiceAccountStatus(ctx *context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount, e *error) { +func (r *NSXServiceAccountReconciler) updateNSXServiceAccountStatus(ctx context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount, e *error) { obj := o if e != nil && *e != nil { obj = o.DeepCopy() @@ -261,7 +250,7 @@ func (r *NSXServiceAccountReconciler) updateNSXServiceAccountStatus(ctx *context obj.Status.Reason = fmt.Sprintf("Error: %v", *e) obj.Status.Conditions = nsxserviceaccount.GenerateNSXServiceAccountConditions(obj.Status.Conditions, obj.Generation, metav1.ConditionFalse, nsxvmwarecomv1alpha1.ConditionReasonRealizationError, fmt.Sprintf("Error: %v", *e)) } - err := r.Client.Status().Update(*ctx, obj) + err := r.Client.Status().Update(ctx, obj) if err != nil { log.Error(err, "update NSXServiceAccount failed", "Namespace", obj.Namespace, "Name", obj.Name, "Status", obj.Status) } else { @@ -269,25 +258,25 @@ func (r *NSXServiceAccountReconciler) updateNSXServiceAccountStatus(ctx *context } } -func updateFail(r *NSXServiceAccountReconciler, c *context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount, e *error) { +func updateFail(r *NSXServiceAccountReconciler, c context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount, e *error) { r.updateNSXServiceAccountStatus(c, o, e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) } -func deleteFail(r *NSXServiceAccountReconciler, c *context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount, e *error) { +func deleteFail(r *NSXServiceAccountReconciler, c context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount, e *error) { r.updateNSXServiceAccountStatus(c, o, e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) } -func updateSuccess(r *NSXServiceAccountReconciler, c *context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount) { +func updateSuccess(r *NSXServiceAccountReconciler, c context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount) { r.updateNSXServiceAccountStatus(c, o, nil) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "ServiceAccount CR has been successfully updated") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) } -func deleteSuccess(r *NSXServiceAccountReconciler, _ *context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount) { +func deleteSuccess(r *NSXServiceAccountReconciler, _ context.Context, o *nsxvmwarecomv1alpha1.NSXServiceAccount) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "ServiceAccount CR has been successfully deleted") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go index 506bf25a5..7e3c621c5 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go @@ -24,7 +24,7 @@ import ( controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" @@ -152,7 +152,7 @@ func TestNSXServiceAccountReconciler_Reconcile(t *testing.T) { Namespace: requestArgs.req.Namespace, Name: requestArgs.req.Name, ResourceVersion: "2", - Finalizers: []string{"nsxserviceaccount.nsx.vmware.com/finalizer"}, + Finalizers: nil, }, Spec: nsxvmwarecomv1alpha1.NSXServiceAccountSpec{}, Status: nsxvmwarecomv1alpha1.NSXServiceAccountStatus{ @@ -555,7 +555,7 @@ func TestNSXServiceAccountReconciler_GarbageCollector(t *testing.T) { name2 := "name2" clusterName2 := "cl1-ns2-name2" uid2 := "00000000-0000-0000-0000-000000000002" - assert.NoError(t, r.Service.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, r.Service.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Name: &clusterName2, Tags: []mpmodel.Tag{{ Scope: &tagScopeNamespace, @@ -590,17 +590,12 @@ func TestNSXServiceAccountReconciler_GarbageCollector(t *testing.T) { } r.Service.SetUpStore() ctx := context.TODO() - cancel := make(chan bool) if tt.prepareFunc != nil { patches := tt.prepareFunc(t, r, ctx) defer patches.Reset() } - go func() { - time.Sleep(50 * time.Millisecond) - cancel <- true - }() - r.GarbageCollector(cancel, 100*time.Millisecond) + r.CollectGarbage(ctx) }) } } @@ -621,7 +616,7 @@ func TestNSXServiceAccountReconciler_updateNSXServiceAccountStatus(t *testing.T) ctx := context.TODO() err := fmt.Errorf("test error") type args struct { - ctx *context.Context + ctx context.Context o *nsxvmwarecomv1alpha1.NSXServiceAccount e *error } @@ -642,7 +637,7 @@ func TestNSXServiceAccountReconciler_updateNSXServiceAccountStatus(t *testing.T) }, }, args: args{ - ctx: &ctx, + ctx: ctx, o: &nsxvmwarecomv1alpha1.NSXServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "name1", @@ -716,7 +711,7 @@ func TestNSXServiceAccountReconciler_updateNSXServiceAccountStatus(t *testing.T) }, }, args: args{ - ctx: &ctx, + ctx: ctx, o: &nsxvmwarecomv1alpha1.NSXServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "name1", @@ -814,7 +809,7 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { name2 := "name2" clusterName2 := "cl1-ns2-name2" uid2 := "00000000-0000-0000-0000-000000000002" - assert.NoError(t, r.Service.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, r.Service.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Name: &clusterName2, Tags: []mpmodel.Tag{{ Scope: &tagScopeNamespace, @@ -831,7 +826,7 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { name3 := "name3" clusterName3 := "cl1-ns3-name3" uid3 := "00000000-0000-0000-0000-000000000003" - assert.NoError(t, r.Service.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, r.Service.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Name: &clusterName3, Tags: []mpmodel.Tag{{ Scope: &tagScopeNamespace, @@ -848,7 +843,7 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { name4 := "name4" clusterName4 := "cl1-ns4-name4" uid4 := "00000000-0000-0000-0000-000000000004" - assert.NoError(t, r.Service.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + assert.NoError(t, r.Service.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &clusterName4, Tags: []model.Tag{{ Scope: &tagScopeNamespace, @@ -876,7 +871,8 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { }) }, args: args{ - nsxServiceAccountUIDSet: sets.New[string]("00000000-0000-0000-0000-000000000002", "00000000-0000-0000-0000-000000000003", "00000000-0000-0000-0000-000000000004"), + nsxServiceAccountUIDSet: sets.New[string]("00000000-0000-0000-0000-000000000002", "00000000-0000-0000-0000-000000000003", + "00000000-0000-0000-0000-000000000004"), nsxServiceAccountList: &nsxvmwarecomv1alpha1.NSXServiceAccountList{Items: []nsxvmwarecomv1alpha1.NSXServiceAccount{{ ObjectMeta: metav1.ObjectMeta{ Namespace: "ns1", diff --git a/pkg/controllers/pod/pod_controller.go b/pkg/controllers/pod/pod_controller.go index ce2e8a5fd..7020e589a 100644 --- a/pkg/controllers/pod/pod_controller.go +++ b/pkg/controllers/pod/pod_controller.go @@ -8,12 +8,10 @@ import ( "fmt" "os" "strings" - "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" apimachineryruntime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" @@ -32,7 +30,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log MetricResTypePod = common.MetricResTypePod ) @@ -73,7 +71,7 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R controllerutil.AddFinalizer(pod, servicecommon.PodFinalizerName) if err := r.Client.Update(ctx, pod); err != nil { log.Error(err, "add finalizer", "pod", req.NamespacedName) - updateFail(r, &ctx, pod, &err) + updateFail(r, ctx, pod, &err) return common.ResultRequeue, err } log.Info("added finalizer on pod", "pod", req.NamespacedName) @@ -91,7 +89,7 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R log.Error(err, "failed to get node ID for pod", "pod.Name", req.NamespacedName, "pod.UID", pod.UID, "node", pod.Spec.NodeName) return common.ResultRequeue, err } - contextID := *node.Id + contextID := *node.UniqueId nsxSubnet, err := r.SubnetService.GetSubnetByPath(nsxSubnetPath) if err != nil { return common.ResultRequeue, err @@ -99,35 +97,36 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R nsxSubnetPortState, err := r.SubnetPortService.CreateOrUpdateSubnetPort(pod, nsxSubnet, contextID, &pod.ObjectMeta.Labels) if err != nil { log.Error(err, "failed to create or update NSX subnet port, would retry exponentially", "pod.Name", req.NamespacedName, "pod.UID", pod.UID) - updateFail(r, &ctx, pod, &err) + updateFail(r, ctx, pod, &err) return common.ResultRequeue, err } podAnnotationChanges := map[string]string{ servicecommon.AnnotationPodMAC: strings.Trim(*nsxSubnetPortState.RealizedBindings[0].Binding.MacAddress, "\""), servicecommon.AnnotationPodAttachment: *nsxSubnetPortState.Attachment.Id, } - err = util.UpdateK8sResourceAnnotation(r.Client, &ctx, pod, podAnnotationChanges) + err = util.UpdateK8sResourceAnnotation(r.Client, ctx, pod, podAnnotationChanges) if err != nil { log.Error(err, "failed to update pod annotation", "pod.Name", req.NamespacedName, "pod.UID", pod.UID, "podAnnotationChanges", podAnnotationChanges) return common.ResultNormal, err } - updateSuccess(r, &ctx, pod) + updateSuccess(r, ctx, pod) } else { if controllerutil.ContainsFinalizer(pod, servicecommon.PodFinalizerName) { metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypePod) - if err := r.SubnetPortService.DeleteSubnetPort(pod.UID); err != nil { + subnetPortID := r.SubnetPortService.BuildSubnetPortId(&pod.ObjectMeta) + if err := r.SubnetPortService.DeleteSubnetPort(subnetPortID); err != nil { log.Error(err, "deletion failed, would retry exponentially", "pod", req.NamespacedName) - deleteFail(r, &ctx, pod, &err) + deleteFail(r, ctx, pod, &err) return common.ResultRequeue, err } controllerutil.RemoveFinalizer(pod, servicecommon.PodFinalizerName) if err := r.Client.Update(ctx, pod); err != nil { log.Error(err, "deletion failed, would retry exponentially", "pod", req.NamespacedName) - deleteFail(r, &ctx, pod, &err) + deleteFail(r, ctx, pod, &err) return common.ResultRequeue, err } log.Info("removed finalizer", "pod", req.NamespacedName) - deleteSuccess(r, &ctx, pod) + deleteSuccess(r, ctx, pod) } else { log.Info("finalizers cannot be recognized", "pod", req.NamespacedName) } @@ -143,7 +142,7 @@ func (r *PodReconciler) GetNodeByName(nodeName string) (*model.HostTransportNode if len(nodes) > 1 { var nodeIDs []string for _, node := range nodes { - nodeIDs = append(nodeIDs, *node.Id) + nodeIDs = append(nodeIDs, *node.UniqueId) } return nil, fmt.Errorf("multiple node IDs found for node %s: %v", nodeName, nodeIDs) } @@ -183,6 +182,7 @@ func StartPodController(mgr ctrl.Manager, subnetPortService *subnetport.SubnetPo log.Error(err, "failed to create controller", "controller", "Pod") os.Exit(1) } + go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, podPortReconciler.CollectGarbage) } // Start setup manager and launch GC @@ -191,75 +191,65 @@ func (r *PodReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } -// GarbageCollector collect Pod which has been removed from crd. -// cancel is used to break the loop during UT -func (r *PodReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage collect Pod which has been removed from crd. +func (r *PodReconciler) CollectGarbage(ctx context.Context) { log.Info("pod garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForPod() - if len(nsxSubnetPortSet) == 0 { - continue - } - podList := &v1.PodList{} - err := r.Client.List(ctx, podList) - if err != nil { - log.Error(err, "failed to list Pod") - continue - } + nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForPod() + if len(nsxSubnetPortSet) == 0 { + return + } + podList := &v1.PodList{} + err := r.Client.List(ctx, podList) + if err != nil { + log.Error(err, "failed to list Pod") + return + } - PodSet := sets.NewString() - for _, pod := range podList.Items { - PodSet.Insert(string(pod.UID)) - } + PodSet := sets.New[string]() + for _, pod := range podList.Items { + subnetPortID := r.SubnetPortService.BuildSubnetPortId(&pod.ObjectMeta) + PodSet.Insert(subnetPortID) + } - for elem := range nsxSubnetPortSet { - if PodSet.Has(elem) { - continue - } - log.V(1).Info("GC collected Pod", "UID", elem) - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypePod) - err = r.SubnetPortService.DeleteSubnetPort(types.UID(elem)) - if err != nil { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypePod) - } else { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypePod) - } + diffSet := nsxSubnetPortSet.Difference(PodSet) + for elem := range diffSet { + log.V(1).Info("GC collected Pod", "NSXSubnetPortID", elem) + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypePod) + err = r.SubnetPortService.DeleteSubnetPort(elem) + if err != nil { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypePod) + } else { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypePod) } } } -func updateFail(r *PodReconciler, c *context.Context, o *v1.Pod, e *error) { +func updateFail(r *PodReconciler, c context.Context, o *v1.Pod, e *error) { r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResTypePod) } -func deleteFail(r *PodReconciler, c *context.Context, o *v1.Pod, e *error) { +func deleteFail(r *PodReconciler, c context.Context, o *v1.Pod, e *error) { r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypePod) } -func updateSuccess(r *PodReconciler, c *context.Context, o *v1.Pod) { +func updateSuccess(r *PodReconciler, c context.Context, o *v1.Pod) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "Pod CR has been successfully updated") metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResTypePod) } -func deleteSuccess(r *PodReconciler, _ *context.Context, o *v1.Pod) { +func deleteSuccess(r *PodReconciler, _ context.Context, o *v1.Pod) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "Pod CR has been successfully deleted") metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypePod) } func (r *PodReconciler) GetSubnetPathForPod(ctx context.Context, pod *v1.Pod) (string, error) { - subnetPath := r.SubnetPortService.GetSubnetPathForSubnetPortFromStore(string(pod.UID)) + subnetPortIDForPod := r.SubnetPortService.BuildSubnetPortId(&pod.ObjectMeta) + subnetPath := r.SubnetPortService.GetSubnetPathForSubnetPortFromStore(subnetPortIDForPod) if len(subnetPath) > 0 { log.V(1).Info("NSX subnet port had been created, returning the existing NSX subnet path", "pod.UID", pod.UID, "subnetPath", subnetPath) return subnetPath, nil diff --git a/pkg/controllers/securitypolicy/namespace_handler.go b/pkg/controllers/securitypolicy/namespace_handler.go index d42b2dab0..f51a2db2f 100644 --- a/pkg/controllers/securitypolicy/namespace_handler.go +++ b/pkg/controllers/securitypolicy/namespace_handler.go @@ -21,7 +21,8 @@ import ( // we should reconcile the corresponding security policy. type EnqueueRequestForNamespace struct { - Client client.Client + Client client.Client + SecurityPolicyReconciler *SecurityPolicyReconciler } func (e *EnqueueRequestForNamespace) Create(_ context.Context, _ event.CreateEvent, _ workqueue.RateLimitingInterface) { @@ -65,7 +66,7 @@ func (e *EnqueueRequestForNamespace) Update(_ context.Context, updateEvent event return } - err = reconcileSecurityPolicy(e.Client, podList.Items, l) + err = reconcileSecurityPolicy(e.SecurityPolicyReconciler, e.Client, podList.Items, l) if err != nil { log.Error(err, "failed to reconcile security policy for namedport check") } diff --git a/pkg/controllers/securitypolicy/namespace_handler_test.go b/pkg/controllers/securitypolicy/namespace_handler_test.go index 10a0fa3cc..037097ee8 100644 --- a/pkg/controllers/securitypolicy/namespace_handler_test.go +++ b/pkg/controllers/securitypolicy/namespace_handler_test.go @@ -125,7 +125,7 @@ func TestEnqueueRequestForNamespace_Update(t *testing.T) { a.Items = podList.Items return nil }) - patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(client client.Client, pods []v1.Pod, + patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(r *SecurityPolicyReconciler, client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface, ) error { return nil diff --git a/pkg/controllers/securitypolicy/pod_handler.go b/pkg/controllers/securitypolicy/pod_handler.go index bab18b7fc..07b3ac065 100644 --- a/pkg/controllers/securitypolicy/pod_handler.go +++ b/pkg/controllers/securitypolicy/pod_handler.go @@ -25,7 +25,8 @@ import ( // new pod or old pod, we should reconcile the security policy. type EnqueueRequestForPod struct { - Client client.Client + Client client.Client + SecurityPolicyReconciler *SecurityPolicyReconciler } func (e *EnqueueRequestForPod) Create(_ context.Context, createEvent event.CreateEvent, q workqueue.RateLimitingInterface) { @@ -70,7 +71,7 @@ func (e *EnqueueRequestForPod) Raw(evt interface{}, q workqueue.RateLimitingInte return } pods = append(pods, *pod) - err := reconcileSecurityPolicy(e.Client, pods, q) + err := reconcileSecurityPolicy(e.SecurityPolicyReconciler, e.Client, pods, q) if err != nil { log.Error(err, "failed to reconcile security policy") } diff --git a/pkg/controllers/securitypolicy/pod_hanlder_test.go b/pkg/controllers/securitypolicy/pod_handler_test.go similarity index 89% rename from pkg/controllers/securitypolicy/pod_hanlder_test.go rename to pkg/controllers/securitypolicy/pod_handler_test.go index 928049c77..8ad9076b2 100644 --- a/pkg/controllers/securitypolicy/pod_hanlder_test.go +++ b/pkg/controllers/securitypolicy/pod_handler_test.go @@ -72,7 +72,7 @@ func TestEnqueueRequestForPod_Raw(t *testing.T) { }{ {"1", fields{}, args{evt, nil}}, } - patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(client client.Client, pods []v1.Pod, + patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(r *SecurityPolicyReconciler, client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface, ) error { return nil @@ -115,7 +115,7 @@ func TestEnqueueRequestForPod_Create(t *testing.T) { }{ {"1", fields{}, args{evt, nil}}, } - patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(client client.Client, pods []v1.Pod, + patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(r *SecurityPolicyReconciler, client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface, ) error { return nil @@ -163,7 +163,7 @@ func TestEnqueueRequestForPod_Update(t *testing.T) { }{ {"1", fields{}, args{evt, nil}}, } - patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(client client.Client, pods []v1.Pod, + patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(r *SecurityPolicyReconciler, client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface, ) error { return nil @@ -206,7 +206,7 @@ func TestEnqueueRequestForPod_Delete(t *testing.T) { }{ {"1", fields{}, args{evt, nil}}, } - patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(client client.Client, pods []v1.Pod, + patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(r *SecurityPolicyReconciler, client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface, ) error { return nil @@ -249,7 +249,7 @@ func TestEnqueueRequestForPod_Generic(t *testing.T) { }{ {"1", fields{}, args{evt, nil}}, } - patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(client client.Client, pods []v1.Pod, + patches := gomonkey.ApplyFunc(reconcileSecurityPolicy, func(r *SecurityPolicyReconciler, client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface, ) error { return nil diff --git a/pkg/controllers/securitypolicy/securitypolicy_controller.go b/pkg/controllers/securitypolicy/securitypolicy_controller.go index 8394bbf1a..6195fc9a2 100644 --- a/pkg/controllers/securitypolicy/securitypolicy_controller.go +++ b/pkg/controllers/securitypolicy/securitypolicy_controller.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "reflect" - "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,7 +25,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -40,7 +40,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins @@ -55,7 +55,7 @@ type SecurityPolicyReconciler struct { Recorder record.EventRecorder } -func updateFail(r *SecurityPolicyReconciler, c *context.Context, o *v1alpha1.SecurityPolicy, e *error) { +func updateFail(r *SecurityPolicyReconciler, c context.Context, o *v1alpha1.SecurityPolicy, e *error) { r.setSecurityPolicyReadyStatusFalse(c, o, metav1.Now(), e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) @@ -69,25 +69,31 @@ func k8sClient(mgr ctrl.Manager) client.Client { return c } -func deleteFail(r *SecurityPolicyReconciler, c *context.Context, o *v1alpha1.SecurityPolicy, e *error) { +func deleteFail(r *SecurityPolicyReconciler, c context.Context, o *v1alpha1.SecurityPolicy, e *error) { r.setSecurityPolicyReadyStatusFalse(c, o, metav1.Now(), e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) } -func updateSuccess(r *SecurityPolicyReconciler, c *context.Context, o *v1alpha1.SecurityPolicy) { +func updateSuccess(r *SecurityPolicyReconciler, c context.Context, o *v1alpha1.SecurityPolicy) { r.setSecurityPolicyReadyStatusTrue(c, o, metav1.Now()) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "SecurityPolicy CR has been successfully updated") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) } -func deleteSuccess(r *SecurityPolicyReconciler, _ *context.Context, o *v1alpha1.SecurityPolicy) { +func deleteSuccess(r *SecurityPolicyReconciler, _ context.Context, o *v1alpha1.SecurityPolicy) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "SecurityPolicy CR has been successfully deleted") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } func (r *SecurityPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - obj := &v1alpha1.SecurityPolicy{} + var obj client.Object + if r.Service.NSXConfig.EnableVPCNetwork { + obj = &crdv1alpha1.SecurityPolicy{} + } else { + obj = &v1alpha1.SecurityPolicy{} + } + log.Info("reconciling securitypolicy CR", "securitypolicy", req.NamespacedName) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) @@ -96,22 +102,36 @@ func (r *SecurityPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ResultNormal, client.IgnoreNotFound(err) } + isZero := false + finalizerName := servicecommon.T1SecurityPolicyFinalizerName + realObj := &v1alpha1.SecurityPolicy{} + switch obj.(type) { + case *crdv1alpha1.SecurityPolicy: + o := obj.(*crdv1alpha1.SecurityPolicy) + isZero = o.ObjectMeta.DeletionTimestamp.IsZero() + finalizerName = servicecommon.SecurityPolicyFinalizerName + realObj = securitypolicy.VPCToT1(o) + case *v1alpha1.SecurityPolicy: + realObj = obj.(*v1alpha1.SecurityPolicy) + isZero = realObj.ObjectMeta.DeletionTimestamp.IsZero() + } + // Since SecurityPolicy service can only be activated from NSX 3.2.0 onwards, // So need to check NSX version before starting SecurityPolicy reconcile if !r.Service.NSXClient.NSXCheckVersion(nsx.SecurityPolicy) { err := errors.New("NSX version check failed, SecurityPolicy feature is not supported") - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, realObj, &err) // if NSX version check fails, it will be put back to reconcile queue and be reconciled after 5 minutes return ResultRequeueAfter5mins, nil } - if obj.ObjectMeta.DeletionTimestamp.IsZero() { + if isZero { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType) - if !controllerutil.ContainsFinalizer(obj, servicecommon.SecurityPolicyFinalizerName) { - controllerutil.AddFinalizer(obj, servicecommon.SecurityPolicyFinalizerName) + if !controllerutil.ContainsFinalizer(obj, finalizerName) { + controllerutil.AddFinalizer(obj, finalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "add finalizer", "securitypolicy", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, realObj, &err) return ResultRequeue, err } log.V(1).Info("added finalizer on securitypolicy CR", "securitypolicy", req.NamespacedName) @@ -120,19 +140,19 @@ func (r *SecurityPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reque if isCRInSysNs, err := util.IsSystemNamespace(r.Client, req.Namespace, nil); err != nil { err = errors.New("fetch namespace associated with security policy CR failed") log.Error(err, "would retry exponentially", "securitypolicy", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, realObj, &err) return ResultRequeue, err } else if isCRInSysNs { err = errors.New("security Policy CR cannot be created in System Namespace") log.Error(err, "", "securitypolicy", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, realObj, &err) return ResultNormal, nil } - if err := r.Service.CreateOrUpdateSecurityPolicy(obj); err != nil { + if err := r.Service.CreateOrUpdateSecurityPolicy(realObj); err != nil { if errors.As(err, &nsxutil.RestrictionError{}) { log.Error(err, err.Error(), "securitypolicy", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, realObj, &err) return ResultNormal, nil } // check if invalid license @@ -156,26 +176,26 @@ func (r *SecurityPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reque } } log.Error(err, "create or update failed, would retry exponentially", "securitypolicy", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, realObj, &err) return ResultRequeue, err } - updateSuccess(r, &ctx, obj) + updateSuccess(r, ctx, realObj) } else { - if controllerutil.ContainsFinalizer(obj, servicecommon.SecurityPolicyFinalizerName) { + if controllerutil.ContainsFinalizer(obj, finalizerName) { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) - if err := r.Service.DeleteSecurityPolicy(obj, false, servicecommon.ResourceTypeSecurityPolicy); err != nil { + if err := r.Service.DeleteSecurityPolicy(realObj.UID, false, servicecommon.ResourceTypeSecurityPolicy); err != nil { log.Error(err, "deletion failed, would retry exponentially", "securitypolicy", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) + deleteFail(r, ctx, realObj, &err) return ResultRequeue, err } - controllerutil.RemoveFinalizer(obj, servicecommon.SecurityPolicyFinalizerName) + controllerutil.RemoveFinalizer(obj, finalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "deletion failed, would retry exponentially", "securitypolicy", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) + deleteFail(r, ctx, realObj, &err) return ResultRequeue, err } log.V(1).Info("removed finalizer", "securitypolicy", req.NamespacedName) - deleteSuccess(r, &ctx, obj) + deleteSuccess(r, ctx, realObj) } else { // only print a message because it's not a normal case log.Info("finalizers cannot be recognized", "securitypolicy", req.NamespacedName) @@ -185,7 +205,7 @@ func (r *SecurityPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ResultNormal, nil } -func (r *SecurityPolicyReconciler) setSecurityPolicyReadyStatusTrue(ctx *context.Context, secPolicy *v1alpha1.SecurityPolicy, transitionTime metav1.Time) { +func (r *SecurityPolicyReconciler) setSecurityPolicyReadyStatusTrue(ctx context.Context, secPolicy *v1alpha1.SecurityPolicy, transitionTime metav1.Time) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -198,7 +218,7 @@ func (r *SecurityPolicyReconciler) setSecurityPolicyReadyStatusTrue(ctx *context r.updateSecurityPolicyStatusConditions(ctx, secPolicy, newConditions) } -func (r *SecurityPolicyReconciler) setSecurityPolicyReadyStatusFalse(ctx *context.Context, secPolicy *v1alpha1.SecurityPolicy, transitionTime metav1.Time, err *error) { +func (r *SecurityPolicyReconciler) setSecurityPolicyReadyStatusFalse(ctx context.Context, secPolicy *v1alpha1.SecurityPolicy, transitionTime metav1.Time, err *error) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -214,7 +234,7 @@ func (r *SecurityPolicyReconciler) setSecurityPolicyReadyStatusFalse(ctx *contex r.updateSecurityPolicyStatusConditions(ctx, secPolicy, newConditions) } -func (r *SecurityPolicyReconciler) updateSecurityPolicyStatusConditions(ctx *context.Context, secPolicy *v1alpha1.SecurityPolicy, newConditions []v1alpha1.Condition) { +func (r *SecurityPolicyReconciler) updateSecurityPolicyStatusConditions(ctx context.Context, secPolicy *v1alpha1.SecurityPolicy, newConditions []v1alpha1.Condition) { conditionsUpdated := false for i := range newConditions { if r.mergeSecurityPolicyStatusCondition(ctx, secPolicy, &newConditions[i]) { @@ -222,13 +242,24 @@ func (r *SecurityPolicyReconciler) updateSecurityPolicyStatusConditions(ctx *con } } if conditionsUpdated { - r.Client.Status().Update(*ctx, secPolicy) + if r.Service.NSXConfig.EnableVPCNetwork { + finalObj := securitypolicy.T1ToVPC(secPolicy) + err := r.Client.Status().Update(ctx, finalObj) + if err != nil { + log.Error(err, "") + } + } else { + err := r.Client.Status().Update(ctx, secPolicy) + if err != nil { + log.Error(err, "") + } + } log.V(1).Info("updated SecurityPolicy", "Name", secPolicy.Name, "Namespace", secPolicy.Namespace, "New Conditions", newConditions) } } -func (r *SecurityPolicyReconciler) mergeSecurityPolicyStatusCondition(ctx *context.Context, secPolicy *v1alpha1.SecurityPolicy, newCondition *v1alpha1.Condition) bool { +func (r *SecurityPolicyReconciler) mergeSecurityPolicyStatusCondition(ctx context.Context, secPolicy *v1alpha1.SecurityPolicy, newCondition *v1alpha1.Condition) bool { matchedCondition := getExistingConditionOfType(newCondition.Type, secPolicy.Status.Conditions) if reflect.DeepEqual(matchedCondition, newCondition) { @@ -256,20 +287,25 @@ func getExistingConditionOfType(conditionType v1alpha1.ConditionType, existingCo } func (r *SecurityPolicyReconciler) setupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.SecurityPolicy{}). + var blr *builder.Builder + if r.Service.NSXConfig.EnableVPCNetwork { + blr = ctrl.NewControllerManagedBy(mgr).For(&crdv1alpha1.SecurityPolicy{}) + } else { + blr = ctrl.NewControllerManagedBy(mgr).For(&v1alpha1.SecurityPolicy{}) + } + return blr. WithOptions( controller.Options{ MaxConcurrentReconciles: common.NumReconcile(), }). Watches( &v1.Namespace{}, - &EnqueueRequestForNamespace{Client: k8sClient(mgr)}, + &EnqueueRequestForNamespace{Client: k8sClient(mgr), SecurityPolicyReconciler: r}, builder.WithPredicates(PredicateFuncsNs), ). Watches( &v1.Pod{}, - &EnqueueRequestForPod{Client: k8sClient(mgr)}, + &EnqueueRequestForPod{Client: k8sClient(mgr), SecurityPolicyReconciler: r}, builder.WithPredicates(PredicateFuncsPod), ). Complete(r) @@ -281,92 +317,115 @@ func (r *SecurityPolicyReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } -// GarbageCollector collect securitypolicy which has been removed from k8s. -// cancel is used to break the loop during UT -func (r *SecurityPolicyReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxPolicySet := r.Service.ListSecurityPolicyID() - if len(nsxPolicySet) == 0 { - continue - } - policyList := &v1alpha1.SecurityPolicyList{} - err := r.Client.List(ctx, policyList) - if err != nil { - log.Error(err, "failed to list SecurityPolicy CR") - continue - } +// CollectGarbage collect securitypolicy which has been removed from k8s, +// it implements the interface GarbageCollector method. +func (r *SecurityPolicyReconciler) CollectGarbage(ctx context.Context) { + log.Info("security policy garbage collector started") + nsxPolicySet := r.Service.ListSecurityPolicyID() + if len(nsxPolicySet) == 0 { + return + } - CRPolicySet := sets.NewString() - for _, policy := range policyList.Items { + var objectList client.ObjectList + if r.Service.NSXConfig.EnableVPCNetwork { + objectList = &crdv1alpha1.SecurityPolicyList{} + } else { + objectList = &v1alpha1.SecurityPolicyList{} + } + err := r.Client.List(ctx, objectList) + if err != nil { + log.Error(err, "failed to list SecurityPolicy CR") + return + } + + CRPolicySet := sets.New[string]() + switch objectList.(type) { + case *crdv1alpha1.SecurityPolicyList: + o := objectList.(*crdv1alpha1.SecurityPolicyList) + for _, policy := range o.Items { + CRPolicySet.Insert(string(policy.UID)) + } + case *v1alpha1.SecurityPolicyList: + o := objectList.(*v1alpha1.SecurityPolicyList) + for _, policy := range o.Items { CRPolicySet.Insert(string(policy.UID)) } + } - for elem := range nsxPolicySet { - if CRPolicySet.Has(elem) { - continue - } - log.V(1).Info("GC collected SecurityPolicy CR", "UID", elem) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) - err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeSecurityPolicy) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) - } + diffSet := nsxPolicySet.Difference(CRPolicySet) + for elem := range diffSet { + log.V(1).Info("GC collected SecurityPolicy CR", "UID", elem) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) + err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeSecurityPolicy) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } } } // It is triggered by associated controller like pod, namespace, etc. -func reconcileSecurityPolicy(client client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface) error { +func reconcileSecurityPolicy(r *SecurityPolicyReconciler, pkgclient client.Client, pods []v1.Pod, q workqueue.RateLimitingInterface) error { podPortNames := getAllPodPortNames(pods) log.V(1).Info("pod named port", "podPortNames", podPortNames) - spList := &v1alpha1.SecurityPolicyList{} - err := client.List(context.Background(), spList) + var spList client.ObjectList + if r.Service.NSXConfig.EnableVPCNetwork { + spList = &crdv1alpha1.SecurityPolicyList{} + } else { + spList = &v1alpha1.SecurityPolicyList{} + } + err := pkgclient.List(context.Background(), spList) if err != nil { log.Error(err, "failed to list all the security policy") return err } - for _, securityPolicy := range spList.Items { - shouldReconcile := false - for _, rule := range securityPolicy.Spec.Rules { - for _, port := range rule.Ports { - if port.Port.Type == intstr.String { - if podPortNames.Has(port.Port.StrVal) { - shouldReconcile = true - break - } + // find the security policy that needs + switch spList.(type) { + case *crdv1alpha1.SecurityPolicyList: + o := spList.(*crdv1alpha1.SecurityPolicyList) + for i := 0; i < len(o.Items); i++ { + realObj := securitypolicy.VPCToT1(&o.Items[i]) + shouldReconcile(realObj, q, podPortNames) + } + case *v1alpha1.SecurityPolicyList: + o := spList.(*v1alpha1.SecurityPolicyList) + for i := 0; i < len(o.Items); i++ { + shouldReconcile(&o.Items[i], q, podPortNames) + } + } + return nil +} + +func shouldReconcile(securityPolicy *v1alpha1.SecurityPolicy, q workqueue.RateLimitingInterface, podPortNames sets.Set[string]) { + shouldReconcile := false + for _, rule := range securityPolicy.Spec.Rules { + for _, port := range rule.Ports { + if port.Port.Type == intstr.String { + if podPortNames.Has(port.Port.StrVal) { + shouldReconcile = true + break } } - if shouldReconcile { - break - } } if shouldReconcile { - log.Info("reconcile security policy because of associated resource change", - "namespace", securityPolicy.Namespace, "name", securityPolicy.Name) - q.Add(reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: securityPolicy.Name, - Namespace: securityPolicy.Namespace, - }, - }) + break } } - return nil + if shouldReconcile { + log.Info("reconcile security policy because of associated resource change", + "namespace", securityPolicy.Namespace, "name", securityPolicy.Name) + q.Add(reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: securityPolicy.Name, + Namespace: securityPolicy.Namespace, + }, + }) + } } func StartSecurityPolicyController(mgr ctrl.Manager, commonService servicecommon.Service, vpcService servicecommon.VPCServiceProvider) { @@ -380,4 +439,5 @@ func StartSecurityPolicyController(mgr ctrl.Manager, commonService servicecommon log.Error(err, "failed to create controller", "controller", "SecurityPolicy") os.Exit(1) } + go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, securityPolicyReconcile.CollectGarbage) } diff --git a/pkg/controllers/securitypolicy/securitypolicy_controller_test.go b/pkg/controllers/securitypolicy/securitypolicy_controller_test.go index a1dde2325..e6810e918 100644 --- a/pkg/controllers/securitypolicy/securitypolicy_controller_test.go +++ b/pkg/controllers/securitypolicy/securitypolicy_controller_test.go @@ -28,21 +28,50 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" - _ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/securitypolicy" ) +func fakeService() *securitypolicy.SecurityPolicyService { + c := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) + cluster, _ := nsx.NewCluster(c) + rc, _ := cluster.NewRestConnector() + + service := &securitypolicy.SecurityPolicyService{ + Service: common.Service{ + NSXClient: &nsx.Client{ + QueryClient: nil, + RestConnector: rc, + RealizedEntitiesClient: nil, + ProjectInfraClient: nil, + NsxConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "k8scl-one:test", + }, + }, + }, + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "k8scl-one:test", + EnableVPCNetwork: false, + }, + }, + }, + } + return service +} + func NewFakeSecurityPolicyReconciler() *SecurityPolicyReconciler { return &SecurityPolicyReconciler{ Client: fake.NewClientBuilder().Build(), Scheme: fake.NewClientBuilder().Build().Scheme(), - Service: nil, + Service: fakeService(), } } @@ -60,7 +89,7 @@ func TestSecurityPolicyController_updateSecurityPolicyStatusConditions(t *testin Reason: "Error occurred while processing the Security Policy CRD. Please check the config and try again", }, } - r.updateSecurityPolicyStatusConditions(&ctx, dummySP, newConditions) + r.updateSecurityPolicyStatusConditions(ctx, dummySP, newConditions) if !reflect.DeepEqual(dummySP.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -86,7 +115,7 @@ func TestSecurityPolicyController_updateSecurityPolicyStatusConditions(t *testin }, } - r.updateSecurityPolicyStatusConditions(&ctx, dummySP, newConditions) + r.updateSecurityPolicyStatusConditions(ctx, dummySP, newConditions) if !reflect.DeepEqual(dummySP.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -102,7 +131,7 @@ func TestSecurityPolicyController_updateSecurityPolicyStatusConditions(t *testin }, } - r.updateSecurityPolicyStatusConditions(&ctx, dummySP, newConditions) + r.updateSecurityPolicyStatusConditions(ctx, dummySP, newConditions) if !reflect.DeepEqual(dummySP.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -118,7 +147,7 @@ func TestSecurityPolicyController_updateSecurityPolicyStatusConditions(t *testin }, } - r.updateSecurityPolicyStatusConditions(&ctx, dummySP, newConditions) + r.updateSecurityPolicyStatusConditions(ctx, dummySP, newConditions) if !reflect.DeepEqual(dummySP.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -143,6 +172,9 @@ func TestSecurityPolicyReconciler_Reconcile(t *testing.T) { Service: common.Service{ NSXClient: &nsx.Client{}, NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + EnableVPCNetwork: false, + }, NsxConfig: &config.NsxConfig{ EnforcementPoint: "vmc-enforcementpoint", }, @@ -171,7 +203,7 @@ func TestSecurityPolicyReconciler_Reconcile(t *testing.T) { }) k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil) patches := gomonkey.ApplyFunc(updateFail, - func(r *SecurityPolicyReconciler, c *context.Context, o *v1alpha1.SecurityPolicy, e *error) { + func(r *SecurityPolicyReconciler, c context.Context, o *v1alpha1.SecurityPolicy, e *error) { }) defer patches.Reset() result, ret := r.Reconcile(ctx, req) @@ -203,7 +235,6 @@ func TestSecurityPolicyReconciler_Reconcile(t *testing.T) { assert.FailNow(t, "should not be called") return nil }) - k8sClient.EXPECT().Update(ctx, gomock.Any(), gomock.Any()).Return(nil) _, ret = r.Reconcile(ctx, req) assert.Equal(t, ret, nil) patch.Reset() @@ -213,12 +244,13 @@ func TestSecurityPolicyReconciler_Reconcile(t *testing.T) { v1sp := obj.(*v1alpha1.SecurityPolicy) time := metav1.Now() v1sp.ObjectMeta.DeletionTimestamp = &time - v1sp.Finalizers = []string{common.SecurityPolicyFinalizerName} + v1sp.Finalizers = []string{common.T1SecurityPolicyFinalizerName} return nil }) patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteSecurityPolicy", func(_ *securitypolicy.SecurityPolicyService, UID interface{}, isVpcCleanup bool) error { return nil }) + k8sClient.EXPECT().Update(ctx, gomock.Any(), gomock.Any()).Return(nil) _, ret = r.Reconcile(ctx, req) assert.Equal(t, ret, nil) patch.Reset() @@ -232,6 +264,9 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { NsxConfig: &config.NsxConfig{ EnforcementPoint: "vmc-enforcementpoint", }, + CoeConfig: &config.CoeConfig{ + EnableVPCNetwork: false, + }, }, }, } @@ -244,7 +279,6 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteSecurityPolicy", func(_ *securitypolicy.SecurityPolicyService, UID interface{}, isVpcCleanup bool) error { return nil }) - cancel := make(chan bool) defer patch.Reset() mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -263,11 +297,7 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -287,11 +317,7 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() @@ -304,17 +330,24 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { return nil }) k8sClient.EXPECT().List(ctx, policyList).Return(nil).Times(0) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) } func TestSecurityPolicyReconciler_Start(t *testing.T) { mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) - service := &securitypolicy.SecurityPolicyService{} + service := &securitypolicy.SecurityPolicyService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + EnforcementPoint: "vmc-enforcementpoint", + }, + CoeConfig: &config.CoeConfig{ + EnableVPCNetwork: false, + }, + }, + }, + } mgr, _ := controllerruntime.NewManager(&rest.Config{}, manager.Options{}) r := &SecurityPolicyReconciler{ Client: k8sClient, @@ -392,6 +425,7 @@ func TestReconcileSecurityPolicy(t *testing.T) { return nil }) + r := NewFakeSecurityPolicyReconciler() mockQueue := mock_client.NewMockInterface(mockCtl) type args struct { @@ -408,7 +442,7 @@ func TestReconcileSecurityPolicy(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.wantErr(t, reconcileSecurityPolicy(tt.args.client, tt.args.pods, tt.args.q), + tt.wantErr(t, reconcileSecurityPolicy(r, tt.args.client, tt.args.pods, tt.args.q), fmt.Sprintf("reconcileSecurityPolicy(%v, %v, %v)", tt.args.client, tt.args.pods, tt.args.q)) }) } diff --git a/pkg/controllers/service/service_lb_controller.go b/pkg/controllers/service/service_lb_controller.go index 9d17a43dc..7bfc09d54 100644 --- a/pkg/controllers/service/service_lb_controller.go +++ b/pkg/controllers/service/service_lb_controller.go @@ -25,7 +25,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue MetricResType = common.MetricResTypeServiceLb @@ -39,7 +39,7 @@ type ServiceLbReconciler struct { Recorder record.EventRecorder } -func updateSuccess(r *ServiceLbReconciler, c *context.Context, lbService *v1.Service) { +func updateSuccess(r *ServiceLbReconciler, c context.Context, lbService *v1.Service) { r.setServiceLbStatus(c, lbService) r.Recorder.Event(lbService, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "LoadBalancer service has been successfully updated") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) @@ -59,17 +59,17 @@ func (r *ServiceLbReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if service.ObjectMeta.DeletionTimestamp.IsZero() { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType) - updateSuccess(r, &ctx, service) + updateSuccess(r, ctx, service) } } return ResultNormal, nil } -func (r *ServiceLbReconciler) setServiceLbStatus(ctx *context.Context, lbService *v1.Service) { +func (r *ServiceLbReconciler) setServiceLbStatus(ctx context.Context, lbService *v1.Service) { ipMode := v1.LoadBalancerIPModeProxy statusUpdated := false - // If tanzu.vmware.com/ingress-ip-mode label with values proxy or vip, + // If nsx.vmware.com/ingress-ip-mode label with values proxy or vip, // the LoadBalancer serivice ipMode status would be set to whatever the label is set to, // Otherwise, it's set to Proxy by default when unset or other invalid values. if labelIpMode, ok := lbService.Labels[servicecommon.LabelLbIngressIpMode]; ok { @@ -87,7 +87,7 @@ func (r *ServiceLbReconciler) setServiceLbStatus(ctx *context.Context, lbService } if statusUpdated { - r.Client.Status().Update(*ctx, lbService) + r.Client.Status().Update(ctx, lbService) log.V(1).Info("updated LB service status ipMode", "Name", lbService.Name, "Namespace", lbService.Namespace, "ipMode", ipMode) } } diff --git a/pkg/controllers/service/service_lb_controller_test.go b/pkg/controllers/service/service_lb_controller_test.go index 0555aac1f..1009ee153 100644 --- a/pkg/controllers/service/service_lb_controller_test.go +++ b/pkg/controllers/service/service_lb_controller_test.go @@ -55,20 +55,20 @@ func TestServiceLbController_setServiceLbStatus(t *testing.T) { } // Case: IPMode is set and ingress-ip-mode label is set as vip. - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, v1.LoadBalancerIPModeVIP, *lbService.Status.LoadBalancer.Ingress[0].IPMode) // Case: IPMode is set and ingress-ip-mode label is set as proxy. lbService.Labels = map[string]string{ servicecommon.LabelLbIngressIpMode: servicecommon.LabelLbIngressIpModeProxyValue, } - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, v1.LoadBalancerIPModeProxy, *lbService.Status.LoadBalancer.Ingress[0].IPMode) // Case: IPMode is set and ingress-ip-mode label is not set. lbService.Labels = nil lbService.Status.LoadBalancer.Ingress[0].IPMode = &vipIpMode - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, v1.LoadBalancerIPModeProxy, *lbService.Status.LoadBalancer.Ingress[0].IPMode) // Case IPMode is not set and label is set as VIP. @@ -81,7 +81,7 @@ func TestServiceLbController_setServiceLbStatus(t *testing.T) { IPMode: nil, }, } - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, v1.LoadBalancerIPModeVIP, *lbService.Status.LoadBalancer.Ingress[0].IPMode) // Case IPMode is not set and label is set as proxy. @@ -94,7 +94,7 @@ func TestServiceLbController_setServiceLbStatus(t *testing.T) { IPMode: nil, }, } - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, v1.LoadBalancerIPModeProxy, *lbService.Status.LoadBalancer.Ingress[0].IPMode) // Case IPMode is not set and label is not set @@ -105,7 +105,7 @@ func TestServiceLbController_setServiceLbStatus(t *testing.T) { IPMode: nil, }, } - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, v1.LoadBalancerIPModeProxy, *lbService.Status.LoadBalancer.Ingress[0].IPMode) // Case Ingress.IP is not set @@ -115,7 +115,7 @@ func TestServiceLbController_setServiceLbStatus(t *testing.T) { IPMode: nil, }, } - r.setServiceLbStatus(&ctx, lbService) + r.setServiceLbStatus(ctx, lbService) assert.Equal(t, (*v1.LoadBalancerIPMode)(nil), lbService.Status.LoadBalancer.Ingress[0].IPMode) } diff --git a/pkg/controllers/staticroute/staticroute_controller.go b/pkg/controllers/staticroute/staticroute_controller.go index 8063f9c2a..9e8e1769b 100644 --- a/pkg/controllers/staticroute/staticroute_controller.go +++ b/pkg/controllers/staticroute/staticroute_controller.go @@ -9,7 +9,6 @@ import ( "os" "reflect" "strings" - "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -31,10 +30,11 @@ import ( _ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" commonservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/staticroute" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins @@ -49,25 +49,25 @@ type StaticRouteReconciler struct { Recorder record.EventRecorder } -func deleteFail(r *StaticRouteReconciler, c *context.Context, o *v1alpha1.StaticRoute, e *error) { +func deleteFail(r *StaticRouteReconciler, c context.Context, o *v1alpha1.StaticRoute, e *error) { r.setStaticRouteReadyStatusFalse(c, o, metav1.Now(), e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeStaticRoute) } -func updateFail(r *StaticRouteReconciler, c *context.Context, o *v1alpha1.StaticRoute, e *error) { +func updateFail(r *StaticRouteReconciler, c context.Context, o *v1alpha1.StaticRoute, e *error) { r.setStaticRouteReadyStatusFalse(c, o, metav1.Now(), e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) } -func updateSuccess(r *StaticRouteReconciler, c *context.Context, o *v1alpha1.StaticRoute) { +func updateSuccess(r *StaticRouteReconciler, c context.Context, o *v1alpha1.StaticRoute) { r.setStaticRouteReadyStatusTrue(c, o, metav1.Now()) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "StaticRoute CR has been successfully updated") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, common.MetricResTypeStaticRoute) } -func deleteSuccess(r *StaticRouteReconciler, _ *context.Context, o *v1alpha1.StaticRoute) { +func deleteSuccess(r *StaticRouteReconciler, _ context.Context, o *v1alpha1.StaticRoute) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "StaticRoute CR has been successfully deleted") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeStaticRoute) } @@ -88,34 +88,38 @@ func (r *StaticRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) controllerutil.AddFinalizer(obj, commonservice.StaticRouteFinalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "add finalizer", "staticroute", req.NamespacedName) - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, obj, &err) return ResultRequeue, err } log.V(1).Info("added finalizer on staticroute CR", "staticroute", req.NamespacedName) } if err := r.Service.CreateOrUpdateStaticRoute(req.Namespace, obj); err != nil { - updateFail(r, &ctx, obj, &err) + updateFail(r, ctx, obj, &err) // TODO: if error is not retriable, not requeue + apierror, errortype := util.DumpAPIError(err) + if apierror != nil { + log.Info("create or update static route failed", "error", apierror, "error type", errortype) + } return ResultRequeue, err } - updateSuccess(r, &ctx, obj) + updateSuccess(r, ctx, obj) } else { if controllerutil.ContainsFinalizer(obj, commonservice.StaticRouteFinalizerName) { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeStaticRoute) // TODO, update the value from 'default' to actual value, get OrgID, ProjectID, VPCID depending on obj.Namespace from vpc store - if err := r.Service.DeleteStaticRoute(req.Namespace, string(obj.UID)); err != nil { + if err := r.Service.DeleteStaticRoute(obj); err != nil { log.Error(err, "delete failed, would retry exponentially", "staticroute", req.NamespacedName) - deleteFail(r, &ctx, obj, &err) + deleteFail(r, ctx, obj, &err) return ResultRequeue, err } controllerutil.RemoveFinalizer(obj, commonservice.StaticRouteFinalizerName) if err := r.Client.Update(ctx, obj); err != nil { - deleteFail(r, &ctx, obj, &err) + deleteFail(r, ctx, obj, &err) return ResultRequeue, err } log.V(1).Info("removed finalizer", "staticroute", req.NamespacedName) - deleteSuccess(r, &ctx, obj) + deleteSuccess(r, ctx, obj) } else { // only print a message because it's not a normal case log.Info("finalizers cannot be recognized", "staticroute", req.NamespacedName) @@ -125,7 +129,7 @@ func (r *StaticRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ResultNormal, nil } -func (r *StaticRouteReconciler) setStaticRouteReadyStatusTrue(ctx *context.Context, staticRoute *v1alpha1.StaticRoute, transitionTime metav1.Time) { +func (r *StaticRouteReconciler) setStaticRouteReadyStatusTrue(ctx context.Context, staticRoute *v1alpha1.StaticRoute, transitionTime metav1.Time) { newConditions := []v1alpha1.StaticRouteCondition{ { Type: v1alpha1.Ready, @@ -138,7 +142,7 @@ func (r *StaticRouteReconciler) setStaticRouteReadyStatusTrue(ctx *context.Conte r.updateStaticRouteStatusConditions(ctx, staticRoute, newConditions) } -func (r *StaticRouteReconciler) setStaticRouteReadyStatusFalse(ctx *context.Context, staticRoute *v1alpha1.StaticRoute, transitionTime metav1.Time, err *error) { +func (r *StaticRouteReconciler) setStaticRouteReadyStatusFalse(ctx context.Context, staticRoute *v1alpha1.StaticRoute, transitionTime metav1.Time, err *error) { newConditions := []v1alpha1.StaticRouteCondition{ { Type: v1alpha1.Ready, @@ -151,7 +155,7 @@ func (r *StaticRouteReconciler) setStaticRouteReadyStatusFalse(ctx *context.Cont r.updateStaticRouteStatusConditions(ctx, staticRoute, newConditions) } -func (r *StaticRouteReconciler) updateStaticRouteStatusConditions(ctx *context.Context, staticRoute *v1alpha1.StaticRoute, newConditions []v1alpha1.StaticRouteCondition) { +func (r *StaticRouteReconciler) updateStaticRouteStatusConditions(ctx context.Context, staticRoute *v1alpha1.StaticRoute, newConditions []v1alpha1.StaticRouteCondition) { conditionsUpdated := false for i := range newConditions { if r.mergeStaticRouteStatusCondition(staticRoute, &newConditions[i]) { @@ -159,7 +163,7 @@ func (r *StaticRouteReconciler) updateStaticRouteStatusConditions(ctx *context.C } } if conditionsUpdated { - r.Client.Status().Update(*ctx, staticRoute) + r.Client.Status().Update(ctx, staticRoute) log.V(1).Info("Updated Static Route CRD", "Name", staticRoute.Name, "Namespace", staticRoute.Namespace, "New Conditions", newConditions) } } @@ -213,59 +217,49 @@ func (r *StaticRouteReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - - go r.GarbageCollector(make(chan bool), commonservice.GCInterval) return nil } -// GarbageCollector collect staticroute which has been removed from crd. -// cancel is used to break the loop during UT -func (r *StaticRouteReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxStaticRouteList := r.Service.ListStaticRoute() - if len(nsxStaticRouteList) == 0 { - continue - } +// CollectGarbage collect staticroute which has been removed from crd. +// it implements the interface GarbageCollector method. +func (r *StaticRouteReconciler) CollectGarbage(ctx context.Context) { + log.Info("static route garbage collector started") + nsxStaticRouteList := r.Service.ListStaticRoute() + if len(nsxStaticRouteList) == 0 { + return + } - crdStaticRouteList := &v1alpha1.StaticRouteList{} - err := r.Client.List(ctx, crdStaticRouteList) - if err != nil { - log.Error(err, "failed to list static route CR") + crdStaticRouteList := &v1alpha1.StaticRouteList{} + err := r.Client.List(ctx, crdStaticRouteList) + if err != nil { + log.Error(err, "failed to list static route CR") + return + } + + crdStaticRouteSet := sets.NewString() + for _, sr := range crdStaticRouteList.Items { + crdStaticRouteSet.Insert(string(sr.UID)) + } + + for _, e := range nsxStaticRouteList { + elem := e + UID := r.Service.GetUID(elem) + if UID == nil { continue } - - crdStaticRouteSet := sets.NewString() - for _, sr := range crdStaticRouteList.Items { - crdStaticRouteSet.Insert(string(sr.UID)) + if crdStaticRouteSet.Has(*UID) { + continue } - for _, e := range nsxStaticRouteList { - elem := e - UID := r.Service.GetUID(elem) - if UID == nil { - continue - } - if crdStaticRouteSet.Has(*UID) { - continue - } - - log.V(1).Info("GC collected StaticRoute CR", "UID", elem) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeStaticRoute) - // get orgId, projectId, staticrouteId from path "/orgs//projects//vpcs//static-routes/" - path := strings.Split(*elem.Path, "/") - err = r.Service.DeleteStaticRouteByPath(path[2], path[4], path[6], *elem.Id) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeStaticRoute) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeStaticRoute) - } + log.V(1).Info("GC collected StaticRoute CR", "UID", elem) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeStaticRoute) + // get orgId, projectId, staticrouteId from path "/orgs//projects//vpcs//static-routes/" + path := strings.Split(*elem.Path, "/") + err = r.Service.DeleteStaticRouteByPath(path[2], path[4], path[6], *elem.Id) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeStaticRoute) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeStaticRoute) } } } @@ -281,4 +275,5 @@ func StartStaticRouteController(mgr ctrl.Manager, staticRouteService *staticrout log.Error(err, "failed to create controller", "controller", "StaticRoute") os.Exit(1) } + go common.GenericGarbageCollector(make(chan bool), commonservice.GCInterval, staticRouteReconcile.CollectGarbage) } diff --git a/pkg/controllers/staticroute/staticroute_controller_test.go b/pkg/controllers/staticroute/staticroute_controller_test.go index 1b58f70a9..695f03ed4 100644 --- a/pkg/controllers/staticroute/staticroute_controller_test.go +++ b/pkg/controllers/staticroute/staticroute_controller_test.go @@ -8,7 +8,6 @@ import ( "errors" "reflect" "testing" - "time" gomonkey "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -23,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" @@ -56,7 +55,7 @@ func TestStaticRouteController_updateStaticRouteStatusConditions(t *testing.T) { Reason: "Error occurred while processing the Static Route CRD. Please check the config and try again", }, } - r.updateStaticRouteStatusConditions(&ctx, dummySR, newConditions) + r.updateStaticRouteStatusConditions(ctx, dummySR, newConditions) if !reflect.DeepEqual(dummySR.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -82,7 +81,7 @@ func TestStaticRouteController_updateStaticRouteStatusConditions(t *testing.T) { }, } - r.updateStaticRouteStatusConditions(&ctx, dummySR, newConditions) + r.updateStaticRouteStatusConditions(ctx, dummySR, newConditions) if !reflect.DeepEqual(dummySR.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -98,7 +97,7 @@ func TestStaticRouteController_updateStaticRouteStatusConditions(t *testing.T) { }, } - r.updateStaticRouteStatusConditions(&ctx, dummySR, newConditions) + r.updateStaticRouteStatusConditions(ctx, dummySR, newConditions) if !reflect.DeepEqual(dummySR.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -114,7 +113,7 @@ func TestStaticRouteController_updateStaticRouteStatusConditions(t *testing.T) { }, } - r.updateStaticRouteStatusConditions(&ctx, dummySR, newConditions) + r.updateStaticRouteStatusConditions(ctx, dummySR, newConditions) if !reflect.DeepEqual(dummySR.Status.Conditions, newConditions) { t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") @@ -200,7 +199,7 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { return nil }) - patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, obj *v1alpha1.StaticRoute) error { assert.FailNow(t, "should not be called") return nil }) @@ -218,7 +217,7 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { v1sp.Finalizers = []string{common.StaticRouteFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, obj *v1alpha1.StaticRoute) error { return nil }) _, ret = r.Reconcile(ctx, req) @@ -233,7 +232,7 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { v1sp.Finalizers = []string{common.StaticRouteFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, obj *v1alpha1.StaticRoute) error { return errors.New("delete failed") }) @@ -299,7 +298,6 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRouteByPath", func(_ *staticroute.StaticRouteService, orgId string, projectId string, vpcId string, uid string) error { return nil }) - cancel := make(chan bool) defer patch.Reset() mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -318,11 +316,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -333,7 +327,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { a = append(a, model.StaticRoutes{Id: &id, Tags: tag2}) return a }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, obj *v1alpha1.StaticRoute) error { assert.FailNow(t, "should not be called") return nil }) @@ -344,27 +338,19 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() patch.ApplyMethod(reflect.TypeOf(service), "ListStaticRoute", func(_ *staticroute.StaticRouteService) []model.StaticRoutes { return []model.StaticRoutes{} }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, obj *v1alpha1.StaticRoute) error { assert.FailNow(t, "should not be called") return nil }) k8sClient.EXPECT().List(ctx, srList).Return(nil).Times(0) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) } func TestStaticRouteReconciler_Start(t *testing.T) { diff --git a/pkg/controllers/subnet/namespace_handler.go b/pkg/controllers/subnet/namespace_handler.go index 6e53b0203..ee2f935d3 100644 --- a/pkg/controllers/subnet/namespace_handler.go +++ b/pkg/controllers/subnet/namespace_handler.go @@ -15,7 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" ) // Subnet controller should watch event of namespace, when there are some updates of namespace labels, diff --git a/pkg/controllers/subnet/subnet_controller.go b/pkg/controllers/subnet/subnet_controller.go index 5b170f43e..d8b6ec579 100644 --- a/pkg/controllers/subnet/subnet_controller.go +++ b/pkg/controllers/subnet/subnet_controller.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "reflect" - "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" @@ -21,7 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -32,7 +31,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins @@ -64,28 +63,29 @@ func (r *SubnetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerUpdateTotal, MetricResTypeSubnet) if !controllerutil.ContainsFinalizer(obj, servicecommon.SubnetFinalizerName) { controllerutil.AddFinalizer(obj, servicecommon.SubnetFinalizerName) + + if obj.Spec.AccessMode == "" { + log.Info("obj.Spec.AccessMode set", "subnet", req.NamespacedName) + obj.Spec.AccessMode = v1alpha1.AccessMode(v1alpha1.AccessModePrivate) + } + + if obj.Spec.IPv4SubnetSize == 0 { + vpcNetworkConfig := r.VPCService.GetVPCNetworkConfigByNamespace(obj.Namespace) + if vpcNetworkConfig == nil { + err := fmt.Errorf("operate failed: cannot get configuration for Subnet CR") + log.Error(nil, "failed to find VPCNetworkConfig for Subnet CR", "subnet", req.NamespacedName, "namespace %s", obj.Namespace) + updateFail(r, ctx, obj, "") + return ResultRequeue, err + } + obj.Spec.IPv4SubnetSize = vpcNetworkConfig.DefaultSubnetSize + } if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "add finalizer", "subnet", req.NamespacedName) - updateFail(r, &ctx, obj, "") + updateFail(r, ctx, obj, "") return ResultRequeue, err } log.V(1).Info("added finalizer on subnet CR", "subnet", req.NamespacedName) } - if obj.Spec.AccessMode == "" || obj.Spec.IPv4SubnetSize == 0 { - vpcNetworkConfig := r.VPCService.GetVPCNetworkConfigByNamespace(obj.Namespace) - if vpcNetworkConfig == nil { - err := fmt.Errorf("operate failed: cannot get configuration for Subnet CR") - log.Error(nil, "failed to find VPCNetworkConfig for Subnet CR", "subnet", req.NamespacedName, "namespace %s", obj.Namespace) - updateFail(r, &ctx, obj, "") - return ResultRequeue, err - } - if obj.Spec.AccessMode == "" { - obj.Spec.AccessMode = v1alpha1.AccessMode(vpcNetworkConfig.DefaultSubnetAccessMode) - } - if obj.Spec.IPv4SubnetSize == 0 { - obj.Spec.IPv4SubnetSize = vpcNetworkConfig.DefaultIPv4SubnetSize - } - } tags := r.SubnetService.GenerateSubnetNSTags(obj, obj.Namespace) if tags == nil { return ResultRequeue, errors.New("failed to generate subnet tags") @@ -97,35 +97,35 @@ func (r *SubnetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr if _, err := r.SubnetService.CreateOrUpdateSubnet(obj, vpcInfoList[0], tags); err != nil { if errors.As(err, &util.ExceedTagsError{}) { log.Error(err, "exceed tags limit, would not retry", "subnet", req.NamespacedName) - updateFail(r, &ctx, obj, err.Error()) + updateFail(r, ctx, obj, err.Error()) return ResultNormal, nil } log.Error(err, "operate failed, would retry exponentially", "subnet", req.NamespacedName) - updateFail(r, &ctx, obj, "") + updateFail(r, ctx, obj, "") return ResultRequeue, err } if err := r.updateSubnetStatus(obj); err != nil { log.Error(err, "update subnet status failed, would retry exponentially", "subnet", req.NamespacedName) - updateFail(r, &ctx, obj, "") + updateFail(r, ctx, obj, "") return ResultRequeue, err } - updateSuccess(r, &ctx, obj) + updateSuccess(r, ctx, obj) } else { if controllerutil.ContainsFinalizer(obj, servicecommon.SubnetFinalizerName) { metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnet) if err := r.DeleteSubnet(*obj); err != nil { log.Error(err, "deletion failed, would retry exponentially", "subnet", req.NamespacedName) - deleteFail(r, &ctx, obj, "") + deleteFail(r, ctx, obj, "") return ResultRequeue, err } controllerutil.RemoveFinalizer(obj, servicecommon.SubnetFinalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "deletion failed, would retry exponentially", "subnet", req.NamespacedName) - deleteFail(r, &ctx, obj, "") + deleteFail(r, ctx, obj, "") return ResultRequeue, err } log.V(1).Info("removed finalizer", "subnet", req.NamespacedName) - deleteSuccess(r, &ctx, obj) + deleteSuccess(r, ctx, obj) } else { log.Info("finalizers cannot be recognized", "subnet", req.NamespacedName) } @@ -153,19 +153,25 @@ func (r *SubnetReconciler) updateSubnetStatus(obj *v1alpha1.Subnet) error { if nsxSubnet == nil { return errors.New("failed to get NSX Subnet from store") } - obj.Status.IPAddresses = obj.Status.IPAddresses[:0] + obj.Status.NetworkAddresses = obj.Status.NetworkAddresses[:0] + obj.Status.GatewayAddresses = obj.Status.GatewayAddresses[:0] + obj.Status.DHCPServerAddresses = obj.Status.DHCPServerAddresses[:0] statusList, err := r.SubnetService.GetSubnetStatus(nsxSubnet) if err != nil { return err } for _, status := range statusList { - obj.Status.IPAddresses = append(obj.Status.IPAddresses, *status.NetworkAddress) + obj.Status.NetworkAddresses = append(obj.Status.NetworkAddresses, *status.NetworkAddress) + obj.Status.GatewayAddresses = append(obj.Status.GatewayAddresses, *status.GatewayAddress) + // DHCPServerAddress is only for the subnet with DHCP enabled + if status.DhcpServerAddress != nil { + obj.Status.DHCPServerAddresses = append(obj.Status.DHCPServerAddresses, *status.DhcpServerAddress) + } } - obj.Status.NSXResourcePath = *nsxSubnet.Path return nil } -func (r *SubnetReconciler) setSubnetReadyStatusTrue(ctx *context.Context, subnet *v1alpha1.Subnet, transitionTime metav1.Time) { +func (r *SubnetReconciler) setSubnetReadyStatusTrue(ctx context.Context, subnet *v1alpha1.Subnet, transitionTime metav1.Time) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -178,7 +184,7 @@ func (r *SubnetReconciler) setSubnetReadyStatusTrue(ctx *context.Context, subnet r.updateSubnetStatusConditions(ctx, subnet, newConditions) } -func (r *SubnetReconciler) setSubnetReadyStatusFalse(ctx *context.Context, subnet *v1alpha1.Subnet, transitionTime metav1.Time, msg string) { +func (r *SubnetReconciler) setSubnetReadyStatusFalse(ctx context.Context, subnet *v1alpha1.Subnet, transitionTime metav1.Time, msg string) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -194,7 +200,7 @@ func (r *SubnetReconciler) setSubnetReadyStatusFalse(ctx *context.Context, subne r.updateSubnetStatusConditions(ctx, subnet, newConditions) } -func (r *SubnetReconciler) updateSubnetStatusConditions(ctx *context.Context, subnet *v1alpha1.Subnet, newConditions []v1alpha1.Condition) { +func (r *SubnetReconciler) updateSubnetStatusConditions(ctx context.Context, subnet *v1alpha1.Subnet, newConditions []v1alpha1.Condition) { conditionsUpdated := false for i := range newConditions { if r.mergeSubnetStatusCondition(ctx, subnet, &newConditions[i]) { @@ -202,7 +208,7 @@ func (r *SubnetReconciler) updateSubnetStatusConditions(ctx *context.Context, su } } if conditionsUpdated { - if err := r.Client.Status().Update(*ctx, subnet); err != nil { + if err := r.Client.Status().Update(ctx, subnet); err != nil { log.Error(err, "failed to update subnet status", "Name", subnet.Name, "Namespace", subnet.Namespace) } else { log.Info("updated Subnet", "Name", subnet.Name, "Namespace", subnet.Namespace, "New Conditions", newConditions) @@ -210,7 +216,7 @@ func (r *SubnetReconciler) updateSubnetStatusConditions(ctx *context.Context, su } } -func (r *SubnetReconciler) mergeSubnetStatusCondition(ctx *context.Context, subnet *v1alpha1.Subnet, newCondition *v1alpha1.Condition) bool { +func (r *SubnetReconciler) mergeSubnetStatusCondition(ctx context.Context, subnet *v1alpha1.Subnet, newCondition *v1alpha1.Condition) bool { matchedCondition := getExistingConditionOfType(newCondition.Type, subnet.Status.Conditions) if reflect.DeepEqual(matchedCondition, newCondition) { @@ -237,25 +243,25 @@ func getExistingConditionOfType(conditionType v1alpha1.ConditionType, existingCo return nil } -func updateFail(r *SubnetReconciler, c *context.Context, o *v1alpha1.Subnet, m string) { +func updateFail(r *SubnetReconciler, c context.Context, o *v1alpha1.Subnet, m string) { r.setSubnetReadyStatusFalse(c, o, metav1.Now(), m) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, m) metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResTypeSubnet) } -func deleteFail(r *SubnetReconciler, c *context.Context, o *v1alpha1.Subnet, m string) { +func deleteFail(r *SubnetReconciler, c context.Context, o *v1alpha1.Subnet, m string) { r.setSubnetReadyStatusFalse(c, o, metav1.Now(), m) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, m) metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnet) } -func updateSuccess(r *SubnetReconciler, c *context.Context, o *v1alpha1.Subnet) { +func updateSuccess(r *SubnetReconciler, c context.Context, o *v1alpha1.Subnet) { r.setSubnetReadyStatusTrue(c, o, metav1.Now()) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "Subnet CR has been successfully updated") metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResTypeSubnet) } -func deleteSuccess(r *SubnetReconciler, _ *context.Context, o *v1alpha1.Subnet) { +func deleteSuccess(r *SubnetReconciler, _ context.Context, o *v1alpha1.Subnet) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "Subnet CR has been successfully deleted") metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnet) } @@ -294,6 +300,7 @@ func StartSubnetController(mgr ctrl.Manager, subnetService *subnet.SubnetService log.Error(err, "failed to create controller", "controller", "Subnet") return err } + go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, subnetReconciler.CollectGarbage) return nil } @@ -303,52 +310,44 @@ func (r *SubnetReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } -func (r *SubnetReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage implements the interface GarbageCollector method. +func (r *SubnetReconciler) CollectGarbage(ctx context.Context) { log.Info("subnet garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - crdSubnetList := &v1alpha1.SubnetList{} - err := r.Client.List(ctx, crdSubnetList) - if err != nil { - log.Error(err, "failed to list subnet CR") - continue - } - var nsxSubnetList []*model.VpcSubnet - for _, subnet := range crdSubnetList.Items { - nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnet(string(subnet.UID))...) - } - if len(nsxSubnetList) == 0 { - continue - } + crdSubnetList := &v1alpha1.SubnetList{} + err := r.Client.List(ctx, crdSubnetList) + if err != nil { + log.Error(err, "failed to list subnet CR") + return + } + var nsxSubnetList []*model.VpcSubnet + for _, subnet := range crdSubnetList.Items { + nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnet(string(subnet.UID))...) + } + if len(nsxSubnetList) == 0 { + return + } - crdSubnetIDs := sets.NewString() - for _, sr := range crdSubnetList.Items { - crdSubnetIDs.Insert(string(sr.UID)) - } + crdSubnetIDs := sets.NewString() + for _, sr := range crdSubnetList.Items { + crdSubnetIDs.Insert(string(sr.UID)) + } - for _, elem := range nsxSubnetList { - uid := util.FindTag(elem.Tags, servicecommon.TagScopeSubnetCRUID) - if crdSubnetIDs.Has(uid) { - continue - } + for _, elem := range nsxSubnetList { + uid := util.FindTag(elem.Tags, servicecommon.TagScopeSubnetCRUID) + if crdSubnetIDs.Has(uid) { + continue + } - log.Info("GC collected Subnet CR", "UID", elem) - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeSubnet) - err = r.SubnetService.DeleteSubnet(*elem) - if err != nil { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeSubnet) - } else { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeSubnet) - } + log.Info("GC collected Subnet CR", "UID", elem) + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeSubnet) + err = r.SubnetService.DeleteSubnet(*elem) + if err != nil { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeSubnet) + } else { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeSubnet) } } } diff --git a/pkg/controllers/subnet/subnet_controller_test.go b/pkg/controllers/subnet/subnet_controller_test.go index 28c9d6062..04f680226 100644 --- a/pkg/controllers/subnet/subnet_controller_test.go +++ b/pkg/controllers/subnet/subnet_controller_test.go @@ -4,7 +4,6 @@ import ( "context" "reflect" "testing" - "time" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -13,7 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" @@ -45,7 +44,6 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteSubnet", func(_ *subnet.SubnetService, subnet model.VpcSubnet) error { return nil }) - cancel := make(chan bool) mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -64,11 +62,7 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -90,11 +84,7 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() @@ -106,10 +96,6 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { return nil }) k8sClient.EXPECT().List(ctx, srList).Return(nil).Times(1) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) patch.Reset() } diff --git a/pkg/controllers/subnetport/subnetport_controller.go b/pkg/controllers/subnetport/subnetport_controller.go index 735bfb55c..321065d13 100644 --- a/pkg/controllers/subnetport/subnetport_controller.go +++ b/pkg/controllers/subnetport/subnetport_controller.go @@ -10,7 +10,6 @@ import ( "os" "reflect" "strings" - "time" vmv1alpha1 "github.com/vmware-tanzu/vm-operator/api/v1alpha1" v1 "k8s.io/api/core/v1" @@ -30,7 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -39,10 +38,11 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnet" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnetport" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" + "github.com/vmware-tanzu/nsx-operator/pkg/util" ) var ( - log = logger.Log + log = &logger.Log MetricResTypeSubnetPort = common.MetricResTypeSubnetPort ) @@ -82,7 +82,7 @@ func (r *SubnetPortReconciler) Reconcile(ctx context.Context, req ctrl.Request) controllerutil.AddFinalizer(subnetPort, servicecommon.SubnetPortFinalizerName) if err := r.Client.Update(ctx, subnetPort); err != nil { log.Error(err, "add finalizer", "subnetport", req.NamespacedName) - updateFail(r, &ctx, subnetPort, &err) + updateFail(r, ctx, subnetPort, &err) return common.ResultRequeue, err } log.Info("added finalizer on subnetport CR", "subnetport", req.NamespacedName) @@ -106,10 +106,10 @@ func (r *SubnetPortReconciler) Reconcile(ctx context.Context, req ctrl.Request) nsxSubnetPortState, err := r.SubnetPortService.CreateOrUpdateSubnetPort(subnetPort, nsxSubnet, "", labels) if err != nil { log.Error(err, "failed to create or update NSX subnet port, would retry exponentially", "subnetport", req.NamespacedName) - updateFail(r, &ctx, subnetPort, &err) + updateFail(r, ctx, subnetPort, &err) return common.ResultRequeue, err } - subnetPort.Status.Attachment = v1alpha1.SegmentPortAttachmentState{ID: *nsxSubnetPortState.Attachment.Id} + subnetPort.Status.Attachment = v1alpha1.PortAttachment{ID: *nsxSubnetPortState.Attachment.Id} subnetPort.Status.NetworkInterfaceConfig = v1alpha1.NetworkInterfaceConfig{ IPAddresses: []v1alpha1.NetworkInterfaceIPAddress{ { @@ -131,23 +131,24 @@ func (r *SubnetPortReconciler) Reconcile(ctx context.Context, req ctrl.Request) // If the SubnetPort CR's status changed, let's clean the conditions, to ensure the r.Client.Status().Update in the following updateSuccess will be invoked at any time. subnetPort.Status.Conditions = nil } - updateSuccess(r, &ctx, subnetPort) + updateSuccess(r, ctx, subnetPort) } else { if controllerutil.ContainsFinalizer(subnetPort, servicecommon.SubnetPortFinalizerName) { metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnetPort) - if err := r.SubnetPortService.DeleteSubnetPort(subnetPort.UID); err != nil { + subnetPortID := r.SubnetPortService.BuildSubnetPortId(&subnetPort.ObjectMeta) + if err := r.SubnetPortService.DeleteSubnetPort(subnetPortID); err != nil { log.Error(err, "deletion failed, would retry exponentially", "subnetport", req.NamespacedName) - deleteFail(r, &ctx, subnetPort, &err) + deleteFail(r, ctx, subnetPort, &err) return common.ResultRequeue, err } controllerutil.RemoveFinalizer(subnetPort, servicecommon.SubnetPortFinalizerName) if err := r.Client.Update(ctx, subnetPort); err != nil { log.Error(err, "deletion failed, would retry exponentially", "subnetport", req.NamespacedName) - deleteFail(r, &ctx, subnetPort, &err) + deleteFail(r, ctx, subnetPort, &err) return common.ResultRequeue, err } log.Info("removed finalizer", "subnetport", req.NamespacedName) - deleteSuccess(r, &ctx, subnetPort) + deleteSuccess(r, ctx, subnetPort) } else { log.Info("finalizers cannot be recognized", "subnetport", req.NamespacedName) } @@ -155,14 +156,47 @@ func (r *SubnetPortReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, nil } +func subnetPortNamespaceVMIndexFunc(obj client.Object) []string { + if sp, ok := obj.(*v1alpha1.SubnetPort); !ok { + log.Info("Invalid object", "type", reflect.TypeOf(obj)) + return []string{} + } else { + vm, _, err := common.GetVirtualMachineNameForSubnetPort(sp) + if vm == "" || err != nil { + log.Info("No proper annotation found", "annotations", sp.Annotations) + return []string{} + } + return []string{fmt.Sprintf("%s/%s", sp.Namespace, vm)} + } +} + +func addressBindingNamespaceVMIndexFunc(obj client.Object) []string { + if ab, ok := obj.(*v1alpha1.AddressBinding); !ok { + log.Info("Invalid object", "type", reflect.TypeOf(obj)) + return []string{} + } else { + return []string{fmt.Sprintf("%s/%s", ab.Namespace, ab.Spec.VMName)} + } +} + // SetupWithManager sets up the controller with the Manager. func (r *SubnetPortReconciler) SetupWithManager(mgr ctrl.Manager) error { + if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &v1alpha1.SubnetPort{}, util.SubnetPortNamespaceVMIndexKey, subnetPortNamespaceVMIndexFunc); err != nil { + return err + } + if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &v1alpha1.AddressBinding{}, util.AddressBindingNamespaceVMIndexKey, addressBindingNamespaceVMIndexFunc); err != nil { + return err + } return ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.SubnetPort{}). WithEventFilter( predicate.Funcs{ DeleteFunc: func(e event.DeleteEvent) bool { // Suppress Delete events to avoid filtering them out in the Reconcile function + switch e.Object.(type) { + case *v1alpha1.AddressBinding: + return true + } return false }, }, @@ -172,8 +206,10 @@ func (r *SubnetPortReconciler) SetupWithManager(mgr ctrl.Manager) error { MaxConcurrentReconciles: common.NumReconcile(), }). Watches(&vmv1alpha1.VirtualMachine{}, - handler.EnqueueRequestsFromMapFunc(r.vmMapFunc), - builder.WithPredicates(predicate.LabelChangedPredicate{})). + handler.EnqueueRequestsFromMapFunc(r.vmMapFunc), + builder.WithPredicates(predicate.LabelChangedPredicate{})). + Watches(&v1alpha1.AddressBinding{}, + handler.EnqueueRequestsFromMapFunc(r.addressBindingMapFunc)). Complete(r) // TODO: watch the virtualmachine event and update the labels on NSX subnet port. } @@ -192,7 +228,7 @@ func (r *SubnetPortReconciler) vmMapFunc(_ context.Context, vm client.Object) [] } for _, subnetPort := range subnetPortList.Items { port := subnetPort - vmName, err := common.GetVirtualMachineNameForSubnetPort(&port) + vmName, _, err := common.GetVirtualMachineNameForSubnetPort(&port) if err != nil { // not block the subnetport visiting because of invalid annotations log.Error(err, "failed to get virtualmachine name from subnetport", "subnetPort.UID", subnetPort.UID) @@ -222,6 +258,7 @@ func StartSubnetPortController(mgr ctrl.Manager, subnetPortService *subnetport.S log.Error(err, "failed to create controller", "controller", "SubnetPort") os.Exit(1) } + go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, subnetPortReconciler.CollectGarbage) } // Start setup manager and launch GC @@ -230,54 +267,44 @@ func (r *SubnetPortReconciler) Start(mgr ctrl.Manager) error { if err != nil { return err } - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } -// GarbageCollector collect SubnetPort which has been removed from crd. -// cancel is used to break the loop during UT -func (r *SubnetPortReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage collect SubnetPort which has been removed from crd. +// it implements the interface GarbageCollector method. +func (r *SubnetPortReconciler) CollectGarbage(ctx context.Context) { log.Info("subnetport garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForCR() - if len(nsxSubnetPortSet) == 0 { - continue - } - subnetPortList := &v1alpha1.SubnetPortList{} - err := r.Client.List(ctx, subnetPortList) - if err != nil { - log.Error(err, "failed to list SubnetPort CR") - continue - } + nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForCR() + if len(nsxSubnetPortSet) == 0 { + return + } + subnetPortList := &v1alpha1.SubnetPortList{} + err := r.Client.List(ctx, subnetPortList) + if err != nil { + log.Error(err, "failed to list SubnetPort CR") + return + } - CRSubnetPortSet := sets.NewString() - for _, subnetPort := range subnetPortList.Items { - CRSubnetPortSet.Insert(string(subnetPort.UID)) - } + CRSubnetPortSet := sets.New[string]() + for _, subnetPort := range subnetPortList.Items { + subnetPortID := r.SubnetPortService.BuildSubnetPortId(&subnetPort.ObjectMeta) + CRSubnetPortSet.Insert(subnetPortID) + } - for elem := range nsxSubnetPortSet { - if CRSubnetPortSet.Has(elem) { - continue - } - log.V(1).Info("GC collected SubnetPort CR", "UID", elem) - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnetPort) - err = r.SubnetPortService.DeleteSubnetPort(types.UID(elem)) - if err != nil { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetPort) - } else { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetPort) - } + diffSet := nsxSubnetPortSet.Difference(CRSubnetPortSet) + for elem := range diffSet { + log.V(1).Info("GC collected SubnetPort CR", "UID", elem) + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnetPort) + err = r.SubnetPortService.DeleteSubnetPort(elem) + if err != nil { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetPort) + } else { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetPort) } } } -func (r *SubnetPortReconciler) setSubnetPortReadyStatusTrue(ctx *context.Context, subnetPort *v1alpha1.SubnetPort, transitionTime metav1.Time) { +func (r *SubnetPortReconciler) setSubnetPortReadyStatusTrue(ctx context.Context, subnetPort *v1alpha1.SubnetPort, transitionTime metav1.Time) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -290,7 +317,7 @@ func (r *SubnetPortReconciler) setSubnetPortReadyStatusTrue(ctx *context.Context r.UpdateSubnetPortStatusConditions(ctx, subnetPort, newConditions) } -func (r *SubnetPortReconciler) setSubnetPortReadyStatusFalse(ctx *context.Context, subnetPort *v1alpha1.SubnetPort, transitionTime metav1.Time, err *error) { +func (r *SubnetPortReconciler) setSubnetPortReadyStatusFalse(ctx context.Context, subnetPort *v1alpha1.SubnetPort, transitionTime metav1.Time, err *error) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -306,7 +333,7 @@ func (r *SubnetPortReconciler) setSubnetPortReadyStatusFalse(ctx *context.Contex r.UpdateSubnetPortStatusConditions(ctx, subnetPort, newConditions) } -func (r *SubnetPortReconciler) UpdateSubnetPortStatusConditions(ctx *context.Context, subnetPort *v1alpha1.SubnetPort, newConditions []v1alpha1.Condition) { +func (r *SubnetPortReconciler) UpdateSubnetPortStatusConditions(ctx context.Context, subnetPort *v1alpha1.SubnetPort, newConditions []v1alpha1.Condition) { conditionsUpdated := false for i := range newConditions { if r.mergeSubnetPortStatusCondition(ctx, subnetPort, &newConditions[i]) { @@ -314,13 +341,13 @@ func (r *SubnetPortReconciler) UpdateSubnetPortStatusConditions(ctx *context.Con } } if conditionsUpdated { - r.Client.Status().Update(*ctx, subnetPort) + r.Client.Status().Update(ctx, subnetPort) log.V(1).Info("updated subnet port CR", "Name", subnetPort.Name, "Namespace", subnetPort.Namespace, "New Conditions", newConditions) } } -func (r *SubnetPortReconciler) mergeSubnetPortStatusCondition(ctx *context.Context, subnetPort *v1alpha1.SubnetPort, newCondition *v1alpha1.Condition) bool { +func (r *SubnetPortReconciler) mergeSubnetPortStatusCondition(ctx context.Context, subnetPort *v1alpha1.SubnetPort, newCondition *v1alpha1.Condition) bool { matchedCondition := getExistingConditionOfType(newCondition.Type, subnetPort.Status.Conditions) if reflect.DeepEqual(matchedCondition, newCondition) { @@ -347,31 +374,33 @@ func getExistingConditionOfType(conditionType v1alpha1.ConditionType, existingCo return nil } -func updateFail(r *SubnetPortReconciler, c *context.Context, o *v1alpha1.SubnetPort, e *error) { +func updateFail(r *SubnetPortReconciler, c context.Context, o *v1alpha1.SubnetPort, e *error) { r.setSubnetPortReadyStatusFalse(c, o, metav1.Now(), e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResTypeSubnetPort) } -func deleteFail(r *SubnetPortReconciler, c *context.Context, o *v1alpha1.SubnetPort, e *error) { +func deleteFail(r *SubnetPortReconciler, c context.Context, o *v1alpha1.SubnetPort, e *error) { r.setSubnetPortReadyStatusFalse(c, o, metav1.Now(), e) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetPort) } -func updateSuccess(r *SubnetPortReconciler, c *context.Context, o *v1alpha1.SubnetPort) { +func updateSuccess(r *SubnetPortReconciler, c context.Context, o *v1alpha1.SubnetPort) { r.setSubnetPortReadyStatusTrue(c, o, metav1.Now()) + r.setAddressBindingStatus(c, o) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "SubnetPort CR has been successfully updated") metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResTypeSubnetPort) } -func deleteSuccess(r *SubnetPortReconciler, _ *context.Context, o *v1alpha1.SubnetPort) { +func deleteSuccess(r *SubnetPortReconciler, _ context.Context, o *v1alpha1.SubnetPort) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "SubnetPort CR has been successfully deleted") metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetPort) } func (r *SubnetPortReconciler) GetSubnetPathForSubnetPort(ctx context.Context, subnetPort *v1alpha1.SubnetPort) (string, error) { - subnetPath := r.SubnetPortService.GetSubnetPathForSubnetPortFromStore(string(subnetPort.UID)) + subnetPortID := r.SubnetPortService.BuildSubnetPortId(&subnetPort.ObjectMeta) + subnetPath := r.SubnetPortService.GetSubnetPathForSubnetPortFromStore(subnetPortID) if len(subnetPath) > 0 { log.V(1).Info("NSX subnet port had been created, returning the existing NSX subnet path", "subnetPort.UID", subnetPort.UID, "subnetPath", subnetPath) return subnetPath, nil @@ -386,11 +415,16 @@ func (r *SubnetPortReconciler) GetSubnetPathForSubnetPort(ctx context.Context, s log.Error(err, "subnet CR not found", "subnet CR", namespacedName) return subnetPath, err } - subnetPath = subnet.Status.NSXResourcePath - if len(subnetPath) == 0 { - err := fmt.Errorf("empty NSX resource path from subnet %s", subnet.Name) + subnetList := r.SubnetService.GetSubnetsByIndex(servicecommon.TagScopeSubnetCRUID, string(subnet.GetUID())) + if len(subnetList) == 0 { + err := fmt.Errorf("empty NSX resource path for subnet CR %s(%s)", subnet.Name, subnet.GetUID()) + return subnetPath, err + } else if len(subnetList) > 1 { + err := fmt.Errorf("multiple NSX subnets found for subnet CR %s(%s)", subnet.Name, subnet.GetUID()) + log.Error(err, "failed to get NSX subnet by subnet CR UID", "subnetList", subnetList) return subnetPath, err } + subnetPath = *subnetList[0].Path } else if len(subnetPort.Spec.SubnetSet) > 0 { subnetSet := &v1alpha1.SubnetSet{} namespacedName := types.NamespacedName{ @@ -430,7 +464,9 @@ func (r *SubnetPortReconciler) updateSubnetStatusOnSubnetPort(subnetPort *v1alph return err } // For now, we have an assumption that one subnetport only have one IP address - subnetPort.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress += fmt.Sprintf("/%d", prefix) + if len(subnetPort.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress) > 0 { + subnetPort.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress += fmt.Sprintf("/%d", prefix) + } subnetPort.Status.NetworkInterfaceConfig.IPAddresses[0].Gateway = gateway nsxSubnet, err := r.SubnetService.GetSubnetByPath(nsxSubnetPath) if err != nil { @@ -441,7 +477,7 @@ func (r *SubnetPortReconciler) updateSubnetStatusOnSubnetPort(subnetPort *v1alph } func (r *SubnetPortReconciler) getLabelsFromVirtualMachine(ctx context.Context, subnetPort *v1alpha1.SubnetPort) (*map[string]string, error) { - vmName, err := common.GetVirtualMachineNameForSubnetPort(subnetPort) + vmName, _, err := common.GetVirtualMachineNameForSubnetPort(subnetPort) if vmName == "" { return nil, err } @@ -456,3 +492,85 @@ func (r *SubnetPortReconciler) getLabelsFromVirtualMachine(ctx context.Context, log.Info("got labels from virtualmachine for subnetport", "subnetPort.UID", subnetPort.UID, "vmName", vmName, "labels", vm.ObjectMeta.Labels) return &vm.ObjectMeta.Labels, nil } + +func (r *SubnetPortReconciler) addressBindingMapFunc(ctx context.Context, obj client.Object) []reconcile.Request { + ab, ok := obj.(*v1alpha1.AddressBinding) + if !ok { + log.Info("Invalid object", "type", reflect.TypeOf(obj)) + return nil + } + // skip reconcile if AddressBinding exists and is realized + if ab.Status.IPAddress != "" { + namespacedName := types.NamespacedName{ + Name: ab.Name, + Namespace: ab.Namespace, + } + existingAddressBinding := &v1alpha1.AddressBinding{} + if err := r.Client.Get(context.TODO(), namespacedName, existingAddressBinding); err == nil { + return nil + } + } + spList := &v1alpha1.SubnetPortList{} + spIndexValue := fmt.Sprintf("%s/%s", ab.Namespace, ab.Spec.VMName) + err := r.Client.List(context.TODO(), spList, client.MatchingFields{util.SubnetPortNamespaceVMIndexKey: spIndexValue}) + if err != nil || len(spList.Items) == 0 { + log.Error(err, "Failed to list SubnetPort from cache", "indexValue", spIndexValue) + return nil + } + if ab.Spec.InterfaceName == "" { + if len(spList.Items) == 1 { + log.V(1).Info("Enqueue SubnetPort for default AddressBinding", "namespace", ab.Namespace, "name", ab.Name, "SubnetPortName", spList.Items[0].Name, "VM", ab.Spec.VMName) + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Name: spList.Items[0].Name, + Namespace: spList.Items[0].Namespace, + }, + }} + } else { + log.Info("Found multiple SubnetPorts for a VM, ignore default AddressBinding for SubnetPort", "namespace", ab.Namespace, "name", ab.Name, "subnetPortCount", len(spList.Items), "VM", ab.Spec.VMName) + return nil + } + } + for i, sp := range spList.Items { + vm, port, err := common.GetVirtualMachineNameForSubnetPort(&spList.Items[i]) + if err != nil || vm == "" { + log.Error(err, "Failed to get VM name from SubnetPort", "namespace", sp.Namespace, "name", sp.Name, "annotations", sp.Annotations) + continue + } + if ab.Spec.InterfaceName == port { + log.V(1).Info("Enqueue SubnetPort for AddressBinding", "namespace", ab.Namespace, "name", ab.Name, "SubnetPortName", spList.Items[0].Name, "VM", ab.Spec.VMName, "port", port) + + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Name: sp.Name, + Namespace: sp.Namespace, + }, + }} + } + } + log.Info("No SubnetPort found for AddressBinding", "namespace", ab.Namespace, "name", ab.Name, "VM", ab.Spec.VMName) + return nil +} + +func (r *SubnetPortReconciler) setAddressBindingStatus(ctx context.Context, subnetPort *v1alpha1.SubnetPort) { + subnetPortID := r.SubnetPortService.BuildSubnetPortId(&subnetPort.ObjectMeta) + nsxSubnetPort := r.SubnetPortService.SubnetPortStore.GetByKey(subnetPortID) + if nsxSubnetPort == nil { + log.Info("Missing SubnetPort", "id", subnetPort.UID) + return + } + if nsxSubnetPort.ExternalAddressBinding == nil || nsxSubnetPort.ExternalAddressBinding.ExternalIpAddress == nil { + return + } + ab := r.SubnetPortService.GetAddressBindingBySubnetPort(subnetPort) + if ab == nil { + log.Info("Missing AddressBinding for SubnetPort", "namespace", subnetPort.Namespace, "name", subnetPort.Name) + return + } + if ab.Status.IPAddress != *nsxSubnetPort.ExternalAddressBinding.ExternalIpAddress { + ab = ab.DeepCopy() + ab.Status.IPAddress = *nsxSubnetPort.ExternalAddressBinding.ExternalIpAddress + r.Client.Status().Update(ctx, ab) + log.V(1).Info("Updated AddressBinding CR status", "namespace", ab.Namespace, "name", ab.Name, "status", ab.Status) + } +} diff --git a/pkg/controllers/subnetport/subnetport_controller_test.go b/pkg/controllers/subnetport/subnetport_controller_test.go index 122b4174a..c4855852d 100644 --- a/pkg/controllers/subnetport/subnetport_controller_test.go +++ b/pkg/controllers/subnetport/subnetport_controller_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "testing" - "time" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -12,7 +11,7 @@ import ( "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "k8s.io/apimachinery/pkg/runtime" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" @@ -95,11 +94,11 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { err = errors.New("Update failed") k8sClient.EXPECT().Update(ctx, gomock.Any()).Return(err) patchesSuccess := gomonkey.ApplyFunc(updateSuccess, - func(r *SubnetPortReconciler, c *context.Context, o *v1alpha1.SubnetPort) { + func(r *SubnetPortReconciler, c context.Context, o *v1alpha1.SubnetPort) { }) defer patchesSuccess.Reset() patchesUpdateFail := gomonkey.ApplyFunc(updateFail, - func(r *SubnetPortReconciler, c *context.Context, o *v1alpha1.SubnetPort, e *error) { + func(r *SubnetPortReconciler, c context.Context, o *v1alpha1.SubnetPort, e *error) { }) defer patchesUpdateFail.Reset() _, ret := r.Reconcile(ctx, req) @@ -193,7 +192,7 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { }) err = errors.New("DeleteSubnetPort failed") patchesDeleteSubnetPort := gomonkey.ApplyFunc((*subnetport.SubnetPortService).DeleteSubnetPort, - func(s *subnetport.SubnetPortService, uid types.UID) error { + func(s *subnetport.SubnetPortService, uid string) error { return err }) defer patchesDeleteSubnetPort.Reset() @@ -204,7 +203,7 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { }) defer patchesCreateOrUpdateSubnetPort.Reset() patchesDeleteFail := gomonkey.ApplyFunc(deleteFail, - func(r *SubnetPortReconciler, c *context.Context, o *v1alpha1.SubnetPort, e *error) { + func(r *SubnetPortReconciler, c context.Context, o *v1alpha1.SubnetPort, e *error) { }) defer patchesDeleteFail.Reset() _, ret = r.Reconcile(ctx, req) @@ -223,7 +222,7 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { err = errors.New("Update failed") k8sClient.EXPECT().Update(ctx, gomock.Any()).Return(err) patchesDeleteSubnetPort = gomonkey.ApplyFunc((*subnetport.SubnetPortService).DeleteSubnetPort, - func(s *subnetport.SubnetPortService, uid types.UID) error { + func(s *subnetport.SubnetPortService, uid string) error { return nil }) defer patchesDeleteSubnetPort.Reset() @@ -242,7 +241,7 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { }) k8sClient.EXPECT().Update(ctx, gomock.Any()).Return(nil) patchesDeleteSubnetPort = gomonkey.ApplyFunc((*subnetport.SubnetPortService).DeleteSubnetPort, - func(s *subnetport.SubnetPortService, uid types.UID) error { + func(s *subnetport.SubnetPortService, uid string) error { return nil }) defer patchesDeleteSubnetPort.Reset() @@ -259,7 +258,7 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { return nil }) patchesDeleteSubnetPort = gomonkey.ApplyFunc((*subnetport.SubnetPortService).DeleteSubnetPort, - func(s *subnetport.SubnetPortService, uid types.UID) error { + func(s *subnetport.SubnetPortService, uid string) error { assert.FailNow(t, "should not be called") return nil }) @@ -288,11 +287,10 @@ func TestSubnetPortReconciler_GarbageCollector(t *testing.T) { }) defer patchesListNSXSubnetPortIDForCR.Reset() patchesDeleteSubnetPort := gomonkey.ApplyFunc((*subnetport.SubnetPortService).DeleteSubnetPort, - func(s *subnetport.SubnetPortService, uid types.UID) error { + func(s *subnetport.SubnetPortService, uid string) error { return nil }) defer patchesDeleteSubnetPort.Reset() - cancel := make(chan bool) mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) r := &SubnetPortReconciler{ @@ -306,11 +304,8 @@ func TestSubnetPortReconciler_GarbageCollector(t *testing.T) { a.Items = append(a.Items, v1alpha1.SubnetPort{}) a.Items[0].ObjectMeta = metav1.ObjectMeta{} a.Items[0].UID = "1234" + a.Items[0].Name = "subnetPort1" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(context.Background()) } diff --git a/pkg/controllers/subnetset/namespace_handler.go b/pkg/controllers/subnetset/namespace_handler.go index 86e543470..1098fd596 100644 --- a/pkg/controllers/subnetset/namespace_handler.go +++ b/pkg/controllers/subnetset/namespace_handler.go @@ -15,7 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" ) // SubnetSet controller should watch event of namespace, when there are some updates of namespace labels, diff --git a/pkg/controllers/subnetset/subnetset_controller.go b/pkg/controllers/subnetset/subnetset_controller.go index 625d76bb6..b5b98a7fb 100644 --- a/pkg/controllers/subnetset/subnetset_controller.go +++ b/pkg/controllers/subnetset/subnetset_controller.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "reflect" - "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" @@ -21,7 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -31,7 +30,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResultNormal = common.ResultNormal ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins @@ -62,24 +61,23 @@ func (r *SubnetSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerUpdateTotal, MetricResTypeSubnetSet) if !controllerutil.ContainsFinalizer(obj, servicecommon.SubnetSetFinalizerName) { controllerutil.AddFinalizer(obj, servicecommon.SubnetSetFinalizerName) - if obj.Spec.AccessMode == "" || obj.Spec.IPv4SubnetSize == 0 { + + if obj.Spec.AccessMode == "" { + obj.Spec.AccessMode = v1alpha1.AccessMode(v1alpha1.AccessModePrivate) + } + if obj.Spec.IPv4SubnetSize == 0 { vpcNetworkConfig := r.VPCService.GetVPCNetworkConfigByNamespace(obj.Namespace) if vpcNetworkConfig == nil { err := fmt.Errorf("failed to find VPCNetworkConfig for namespace %s", obj.Namespace) log.Error(err, "operate failed, would retry exponentially", "subnet", req.NamespacedName) - updateFail(r, &ctx, obj, "") + updateFail(r, ctx, obj, "") return ResultRequeue, err } - if obj.Spec.AccessMode == "" { - obj.Spec.AccessMode = v1alpha1.AccessMode(vpcNetworkConfig.DefaultSubnetAccessMode) - } - if obj.Spec.IPv4SubnetSize == 0 { - obj.Spec.IPv4SubnetSize = vpcNetworkConfig.DefaultIPv4SubnetSize - } + obj.Spec.IPv4SubnetSize = vpcNetworkConfig.DefaultSubnetSize } if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "add finalizer", "subnetset", req.NamespacedName) - updateFail(r, &ctx, obj, "") + updateFail(r, ctx, obj, "") return ResultRequeue, err } log.V(1).Info("added finalizer on subnetset CR", "subnetset", req.NamespacedName) @@ -96,30 +94,37 @@ func (r *SubnetSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if len(tags) > servicecommon.TagsCountMax { errorMsg := fmt.Sprintf("tags cannot exceed maximum size 26, tags length: %d", len(tags)) log.Error(nil, "exceed tags limit, would not retry", "subnet", req.NamespacedName) - updateFail(r, &ctx, obj, errorMsg) + updateFail(r, ctx, obj, errorMsg) return ResultNormal, nil } if err := r.SubnetService.UpdateSubnetSetTags(obj.Namespace, nsxSubnets, tags); err != nil { log.Error(err, "failed to update subnetset tags") } } - updateSuccess(r, &ctx, obj) + updateSuccess(r, ctx, obj) } else { if controllerutil.ContainsFinalizer(obj, servicecommon.SubnetSetFinalizerName) { metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnetSet) - if err := r.DeleteSubnetForSubnetSet(*obj, false); err != nil { + hasStaleSubnetPorts, err := r.DeleteSubnetForSubnetSet(*obj, false) + if err != nil { log.Error(err, "deletion failed, would retry exponentially", "subnetset", req.NamespacedName) - deleteFail(r, &ctx, obj, "") + deleteFail(r, ctx, obj, "") + return ResultRequeue, err + } + if hasStaleSubnetPorts { + err := fmt.Errorf("stale subnet ports found while deleting subnetset %v", req.NamespacedName) + log.Error(err, "deletion failed, delete all the subnetports first", "subnetset", req.NamespacedName) + updateFail(r, ctx, obj, err.Error()) return ResultRequeue, err } controllerutil.RemoveFinalizer(obj, servicecommon.SubnetSetFinalizerName) if err := r.Client.Update(ctx, obj); err != nil { log.Error(err, "deletion failed, would retry exponentially", "subnetset", req.NamespacedName) - deleteFail(r, &ctx, obj, "") + deleteFail(r, ctx, obj, "") return ResultRequeue, err } log.V(1).Info("removed finalizer", "subnetset", req.NamespacedName) - deleteSuccess(r, &ctx, obj) + deleteSuccess(r, ctx, obj) } else { log.Info("finalizers cannot be recognized", "subnetset", req.NamespacedName) } @@ -127,30 +132,30 @@ func (r *SubnetSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, nil } -func updateFail(r *SubnetSetReconciler, c *context.Context, o *v1alpha1.SubnetSet, m string) { +func updateFail(r *SubnetSetReconciler, c context.Context, o *v1alpha1.SubnetSet, m string) { r.setSubnetSetReadyStatusFalse(c, o, metav1.Now(), m) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, m) metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResTypeSubnetSet) } -func deleteFail(r *SubnetSetReconciler, c *context.Context, o *v1alpha1.SubnetSet, m string) { +func deleteFail(r *SubnetSetReconciler, c context.Context, o *v1alpha1.SubnetSet, m string) { r.setSubnetSetReadyStatusFalse(c, o, metav1.Now(), m) r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, m) metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) } -func updateSuccess(r *SubnetSetReconciler, c *context.Context, o *v1alpha1.SubnetSet) { +func updateSuccess(r *SubnetSetReconciler, c context.Context, o *v1alpha1.SubnetSet) { r.setSubnetSetReadyStatusTrue(c, o, metav1.Now()) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "SubnetSet CR has been successfully updated") metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResTypeSubnetSet) } -func deleteSuccess(r *SubnetSetReconciler, _ *context.Context, o *v1alpha1.SubnetSet) { +func deleteSuccess(r *SubnetSetReconciler, _ context.Context, o *v1alpha1.SubnetSet) { r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "SubnetSet CR has been successfully deleted") metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) } -func (r *SubnetSetReconciler) setSubnetSetReadyStatusTrue(ctx *context.Context, subnetset *v1alpha1.SubnetSet, transitionTime metav1.Time) { +func (r *SubnetSetReconciler) setSubnetSetReadyStatusTrue(ctx context.Context, subnetset *v1alpha1.SubnetSet, transitionTime metav1.Time) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -163,7 +168,7 @@ func (r *SubnetSetReconciler) setSubnetSetReadyStatusTrue(ctx *context.Context, r.updateSubnetSetStatusConditions(ctx, subnetset, newConditions) } -func (r *SubnetSetReconciler) setSubnetSetReadyStatusFalse(ctx *context.Context, subnetset *v1alpha1.SubnetSet, transitionTime metav1.Time, m string) { +func (r *SubnetSetReconciler) setSubnetSetReadyStatusFalse(ctx context.Context, subnetset *v1alpha1.SubnetSet, transitionTime metav1.Time, m string) { newConditions := []v1alpha1.Condition{ { Type: v1alpha1.Ready, @@ -179,7 +184,7 @@ func (r *SubnetSetReconciler) setSubnetSetReadyStatusFalse(ctx *context.Context, r.updateSubnetSetStatusConditions(ctx, subnetset, newConditions) } -func (r *SubnetSetReconciler) updateSubnetSetStatusConditions(ctx *context.Context, subnetset *v1alpha1.SubnetSet, newConditions []v1alpha1.Condition) { +func (r *SubnetSetReconciler) updateSubnetSetStatusConditions(ctx context.Context, subnetset *v1alpha1.SubnetSet, newConditions []v1alpha1.Condition) { conditionsUpdated := false for i := range newConditions { if r.mergeSubnetSetStatusCondition(ctx, subnetset, &newConditions[i]) { @@ -187,7 +192,7 @@ func (r *SubnetSetReconciler) updateSubnetSetStatusConditions(ctx *context.Conte } } if conditionsUpdated { - if err := r.Client.Status().Update(*ctx, subnetset); err != nil { + if err := r.Client.Status().Update(ctx, subnetset); err != nil { log.Error(err, "failed to update status", "Name", subnetset.Name, "Namespace", subnetset.Namespace) } else { log.Info("updated SubnetSet", "Name", subnetset.Name, "Namespace", subnetset.Namespace, "New Conditions", newConditions) @@ -195,7 +200,7 @@ func (r *SubnetSetReconciler) updateSubnetSetStatusConditions(ctx *context.Conte } } -func (r *SubnetSetReconciler) mergeSubnetSetStatusCondition(ctx *context.Context, subnetset *v1alpha1.SubnetSet, newCondition *v1alpha1.Condition) bool { +func (r *SubnetSetReconciler) mergeSubnetSetStatusCondition(ctx context.Context, subnetset *v1alpha1.SubnetSet, newCondition *v1alpha1.Condition) bool { matchedCondition := getExistingConditionOfType(newCondition.Type, subnetset.Status.Conditions) if reflect.DeepEqual(matchedCondition, newCondition) { @@ -236,60 +241,53 @@ func (r *SubnetSetReconciler) setupWithManager(mgr ctrl.Manager) error { Complete(r) } -// GarbageCollector collect Subnet which there is no port attached on it. -// cancel is used to break the loop during UT -func (r *SubnetSetReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage collect Subnet which there is no port attached on it. +// it implements the interface GarbageCollector method. +func (r *SubnetSetReconciler) CollectGarbage(ctx context.Context) { log.Info("subnetset garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } + subnetSetList := &v1alpha1.SubnetSetList{} + err := r.Client.List(ctx, subnetSetList) + if err != nil { + log.Error(err, "failed to list SubnetSet CR") + return + } + var nsxSubnetList []*model.VpcSubnet + for _, subnetSet := range subnetSetList.Items { + nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnetSet(string(subnetSet.UID))...) + } + if len(nsxSubnetList) == 0 { + return + } - subnetSetList := &v1alpha1.SubnetSetList{} - err := r.Client.List(ctx, subnetSetList) - if err != nil { - log.Error(err, "failed to list SubnetSet CR") - continue - } - var nsxSubnetList []*model.VpcSubnet - for _, subnetSet := range subnetSetList.Items { - nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnetSet(string(subnetSet.UID))...) + subnetSetIDs := sets.New[string]() + for _, subnetSet := range subnetSetList.Items { + if _, err := r.DeleteSubnetForSubnetSet(subnetSet, true); err != nil { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) + } else { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) } - if len(nsxSubnetList) == 0 { + subnetSetIDs.Insert(string(subnetSet.UID)) + } + for _, subnet := range nsxSubnetList { + if !r.SubnetService.IsOrphanSubnet(*subnet, subnetSetIDs) { continue } - - subnetSetIDs := sets.New[string]() - for _, subnetSet := range subnetSetList.Items { - if err := r.DeleteSubnetForSubnetSet(subnetSet, true); err != nil { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) - } else { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) - } - subnetSetIDs.Insert(string(subnetSet.UID)) - } - for _, subnet := range nsxSubnetList { - if !r.SubnetService.IsOrphanSubnet(*subnet, subnetSetIDs) { - continue - } - if err := r.SubnetService.DeleteSubnet(*subnet); err != nil { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) - } else { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) - } + if err := r.SubnetService.DeleteSubnet(*subnet); err != nil { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) + } else { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) } } } -func (r *SubnetSetReconciler) DeleteSubnetForSubnetSet(obj v1alpha1.SubnetSet, updataStatus bool) error { +func (r *SubnetSetReconciler) DeleteSubnetForSubnetSet(obj v1alpha1.SubnetSet, updataStatus bool) (bool, error) { nsxSubnets := r.SubnetService.SubnetStore.GetByIndex(servicecommon.TagScopeSubnetSetCRUID, string(obj.GetUID())) hitError := false + hasStaleSubnetPorts := false for _, subnet := range nsxSubnets { portNums := len(r.SubnetPortService.GetPortsOfSubnet(*subnet.Id)) if portNums > 0 { + hasStaleSubnetPorts = true continue } if err := r.SubnetService.DeleteSubnet(*subnet); err != nil { @@ -300,13 +298,13 @@ func (r *SubnetSetReconciler) DeleteSubnetForSubnetSet(obj v1alpha1.SubnetSet, u } if updataStatus { if err := r.SubnetService.UpdateSubnetSetStatus(&obj); err != nil { - return err + return hasStaleSubnetPorts, err } } if hitError { - return errors.New("error occurs when deleting subnet") + return hasStaleSubnetPorts, errors.New("error occurs when deleting subnet") } - return nil + return hasStaleSubnetPorts, nil } func StartSubnetSetController(mgr ctrl.Manager, subnetService *subnet.SubnetService, @@ -324,6 +322,7 @@ func StartSubnetSetController(mgr ctrl.Manager, subnetService *subnet.SubnetServ log.Error(err, "failed to create controller", "controller", "Subnet") return err } + go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, subnetsetReconciler.CollectGarbage) return nil } @@ -349,6 +348,5 @@ func (r *SubnetSetReconciler) Start(mgr ctrl.Manager, enableWebhook bool) error }, }) } - go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) return nil } diff --git a/pkg/controllers/subnetset/subnetset_webhook.go b/pkg/controllers/subnetset/subnetset_webhook.go index 1597799c9..396a211d1 100644 --- a/pkg/controllers/subnetset/subnetset_webhook.go +++ b/pkg/controllers/subnetset/subnetset_webhook.go @@ -13,7 +13,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) @@ -29,7 +29,7 @@ var NSXOperatorSA = "system:serviceaccount:vmware-system-nsx:ncp-svc-account" type SubnetSetValidator struct { Client client.Client - decoder *admission.Decoder + decoder admission.Decoder } func defaultSubnetSetLabelChanged(oldSubnetSet, subnetSet *v1alpha1.SubnetSet) bool { diff --git a/pkg/controllers/vpc/vpc_controller.go b/pkg/controllers/vpc/vpc_controller.go deleted file mode 100644 index 053f8e3f3..000000000 --- a/pkg/controllers/vpc/vpc_controller.go +++ /dev/null @@ -1,217 +0,0 @@ -/* Copyright © 2023 VMware, Inc. All Rights Reserved. - SPDX-License-Identifier: Apache-2.0 */ - -package vpc - -import ( - "context" - "time" - - apimachineryruntime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/builder" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - - "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" - "github.com/vmware-tanzu/nsx-operator/pkg/logger" - "github.com/vmware-tanzu/nsx-operator/pkg/metrics" - _ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" - commonservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" -) - -var ( - log = logger.Log - ResultNormal = common.ResultNormal - ResultRequeue = common.ResultRequeue - ResultRequeueAfter5mins = common.ResultRequeueAfter5mins - MetricResType = common.MetricResTypeVPC -) - -// VPCReconciler VPCReconcile reconciles a VPC object -type VPCReconciler struct { - Client client.Client - Scheme *apimachineryruntime.Scheme - Service *vpc.VPCService - Recorder record.EventRecorder -} - -func (r *VPCReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - obj := &v1alpha1.VPC{} - log.Info("reconciling VPC CR", "VPC", req.NamespacedName) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, common.MetricResTypeVPC) - - if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { - log.Error(err, "unable to fetch VPC CR", "req", req.NamespacedName) - return common.ResultNormal, client.IgnoreNotFound(err) - } - - if obj.ObjectMeta.DeletionTimestamp.IsZero() { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, common.MetricResTypeVPC) - if !controllerutil.ContainsFinalizer(obj, commonservice.VPCFinalizerName) { - controllerutil.AddFinalizer(obj, commonservice.VPCFinalizerName) - if err := r.Client.Update(ctx, obj); err != nil { - log.Error(err, "add finalizer", "VPC", req.NamespacedName) - updateFail(r, &ctx, obj, &err, r.Client) - return common.ResultRequeue, err - } - log.V(1).Info("added finalizer on VPC CR", "VPC", req.NamespacedName) - } - - createdVpc, nc, err := r.Service.CreateorUpdateVPC(obj) - if err != nil { - log.Error(err, "operate failed, would retry exponentially", "VPC", req.NamespacedName) - updateFail(r, &ctx, obj, &err, r.Client) - return common.ResultRequeueAfter10sec, err - } - err = r.Service.CreateOrUpdateAVIRule(createdVpc, obj.Namespace) - if err != nil { - log.Error(err, "operate failed, would retry exponentially", "VPC", req.NamespacedName) - updateFail(r, &ctx, obj, &err, r.Client) - return common.ResultRequeueAfter10sec, err - } - - snatIP, path, cidr := "", "", "" - // currently, auto snat is not exposed, and use default value True - // checking autosnat to support future extension in vpc configuration - if *createdVpc.ServiceGateway.AutoSnat { - snatIP, err = r.Service.GetDefaultSNATIP(*createdVpc) - if err != nil { - log.Error(err, "failed to read default SNAT ip from VPC", "VPC", createdVpc.Id) - return common.ResultRequeueAfter10sec, err - } - } - - // if lb vpc enabled, read avi subnet path and cidr - // nsx bug, if set LoadBalancerVpcEndpoint.Enabled to false, when read this vpc back, - // LoadBalancerVpcEndpoint.Enabled will become a nil pointer. - if createdVpc.LoadBalancerVpcEndpoint.Enabled != nil && *createdVpc.LoadBalancerVpcEndpoint.Enabled { - path, cidr, err = r.Service.GetAVISubnetInfo(*createdVpc) - if err != nil { - log.Error(err, "failed to read lb subnet path and cidr", "VPC", createdVpc.Id) - return common.ResultRequeueAfter10sec, err - } - } - - updateSuccess(r, &ctx, obj, r.Client, *createdVpc.Path, snatIP, path, cidr, nc.PrivateIPv4CIDRs) - } else { - if controllerutil.ContainsFinalizer(obj, commonservice.VPCFinalizerName) { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeVPC) - vpcs := r.Service.GetVPCsByNamespace(obj.GetNamespace()) - // if nsx resource do not exist, continue to remove finalizer, or the crd can not be removed - if len(vpcs) == 0 { - // when nsx vpc not found in vpc store, skip deleting NSX VPC - log.Info("can not find VPC in store, skip deleting NSX VPC, remove finalizer from VPC CR") - } else { - vpc := vpcs[0] - if err := r.Service.DeleteVPC(*vpc.Path); err != nil { - log.Error(err, "failed to delete VPC CR, would retry exponentially", "VPC", req.NamespacedName) - deleteFail(r, &ctx, obj, &err, r.Client) - return common.ResultRequeueAfter10sec, err - } - - if err := r.Service.DeleteIPBlockInVPC(*vpc); err != nil { - log.Error(err, "failed to delete private ip blocks for VPC", "VPC", req.NamespacedName) - } - } - - controllerutil.RemoveFinalizer(obj, commonservice.VPCFinalizerName) - if err := r.Client.Update(ctx, obj); err != nil { - deleteFail(r, &ctx, obj, &err, r.Client) - return common.ResultRequeue, err - } - log.V(1).Info("removed finalizer", "VPC", req.NamespacedName) - deleteSuccess(r, &ctx, obj) - } else { - // only print a message because it's not a normal case - log.Info("finalizers cannot be recognized", "VPC", req.NamespacedName) - } - } - return common.ResultNormal, nil -} - -func (r *VPCReconciler) setupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.VPC{}). - WithOptions( - controller.Options{ - MaxConcurrentReconciles: common.NumReconcile(), - }). - Watches( - // For created/removed network config, add/remove from vpc network config cache. - // For modified network config, currently only support appending ips to public ip blocks, - // update network config in cache and update nsx vpc object. - &v1alpha1.VPCNetworkConfiguration{}, - &VPCNetworkConfigurationHandler{ - Client: mgr.GetClient(), - vpcService: r.Service, - }, - builder.WithPredicates(VPCNetworkConfigurationPredicate)). - Complete(r) -} - -// Start setup manager and launch GC -func (r *VPCReconciler) Start(mgr ctrl.Manager) error { - err := r.setupWithManager(mgr) - if err != nil { - return err - } - - go r.GarbageCollector(make(chan bool), commonservice.GCInterval) - return nil -} - -// GarbageCollector collect vpc which has been removed from crd. -// cancel is used to break the loop during UT -func (r *VPCReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("VPC garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxVPCList := r.Service.ListVPC() - if len(nsxVPCList) == 0 { - continue - } - - crdVPCList := &v1alpha1.VPCList{} - err := r.Client.List(ctx, crdVPCList) - if err != nil { - log.Error(err, "failed to list VPC CR") - continue - } - - crdVPCSet := sets.NewString() - for _, vc := range crdVPCList.Items { - crdVPCSet.Insert(string(vc.UID)) - } - - for _, elem := range nsxVPCList { - if crdVPCSet.Has(*elem.Id) { - continue - } - - log.V(1).Info("GC collected nsx VPC object", "ID", elem.Id) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeVPC) - err = r.Service.DeleteVPC(*elem.Path) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeVPC) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeVPC) - if err := r.Service.DeleteIPBlockInVPC(elem); err != nil { - log.Error(err, "failed to delete private ip blocks for VPC", "VPC", *elem.DisplayName) - } - log.Info("deleted private ip blocks for VPC", "VPC", *elem.DisplayName) - } - } - } -} diff --git a/pkg/controllers/vpc/vpc_utils.go b/pkg/controllers/vpc/vpc_utils.go deleted file mode 100644 index 2b4bd1580..000000000 --- a/pkg/controllers/vpc/vpc_utils.go +++ /dev/null @@ -1,169 +0,0 @@ -package vpc - -import ( - "context" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - - "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" - "github.com/vmware-tanzu/nsx-operator/pkg/metrics" - types "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -func setVPCReadyStatusFalse(ctx *context.Context, vpc *v1alpha1.VPC, err *error, client client.Client) { - newConditions := []v1alpha1.Condition{ - { - Type: v1alpha1.Ready, - Status: v1.ConditionFalse, - Message: "NSX VPC could not be created/updated", - Reason: fmt.Sprintf("Error occurred while processing the VPC CR. Please check the config and try again. Error: %v", *err), - LastTransitionTime: metav1.Now(), - }, - } - updateVPCStatusConditions(ctx, vpc, newConditions, client, "", "", "", "", []string{}) -} - -func updateVPCStatusConditions(ctx *context.Context, vpc *v1alpha1.VPC, newConditions []v1alpha1.Condition, client client.Client, path string, snatIP string, - subnetPath string, cidr string, privateCidrs []string) { - conditionsUpdated := false - statusUpdated := false - for i := range newConditions { - if mergeVPCStatusCondition(ctx, vpc, &newConditions[i]) { - conditionsUpdated = true - } - } - if vpc.Status.NSXResourcePath != path || vpc.Status.DefaultSNATIP != snatIP || vpc.Status.LBSubnetPath != subnetPath || vpc.Status.LBSubnetCIDR != cidr || len(vpc.Status.PrivateIPv4CIDRs) != len(privateCidrs) { - vpc.Status.NSXResourcePath = path - vpc.Status.DefaultSNATIP = snatIP - vpc.Status.LBSubnetPath = subnetPath - vpc.Status.LBSubnetCIDR = cidr - vpc.Status.PrivateIPv4CIDRs = privateCidrs - statusUpdated = true - } - - if conditionsUpdated || statusUpdated { - - client.Status().Update(*ctx, vpc) - log.V(1).Info("updated VPC CRD", "Name", vpc.Name, "Namespace", vpc.Namespace, "Conditions", newConditions) - } -} - -func deleteFail(r *VPCReconciler, c *context.Context, o *v1alpha1.VPC, e *error, client client.Client) { - setVPCReadyStatusFalse(c, o, e, client) - r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeVPC) -} - -func updateFail(r *VPCReconciler, c *context.Context, o *v1alpha1.VPC, e *error, client client.Client) { - setVPCReadyStatusFalse(c, o, e, client) - r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) -} - -func updateSuccess(r *VPCReconciler, c *context.Context, o *v1alpha1.VPC, client client.Client, - path string, snatIP string, subnetPath string, cidr string, privateCidrs []string) { - setVPCReadyStatusTrue(c, o, client, path, snatIP, subnetPath, cidr, privateCidrs) - r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "VPC CR has been successfully updated") - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, common.MetricResTypeVPC) -} - -func deleteSuccess(r *VPCReconciler, _ *context.Context, o *v1alpha1.VPC) { - r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "VPC CR has been successfully deleted") - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeVPC) -} - -func setVPCReadyStatusTrue(ctx *context.Context, vpc *v1alpha1.VPC, client client.Client, path, snatIP, subnetPath, cidr string, privateCidrs []string) { - newConditions := []v1alpha1.Condition{ - { - Type: v1alpha1.Ready, - Status: v1.ConditionTrue, - Message: "NSX VPC has been successfully created/updated", - Reason: "NSX API returned 200 response code for PATCH", - LastTransitionTime: metav1.Now(), - }, - } - updateVPCStatusConditions(ctx, vpc, newConditions, client, path, snatIP, subnetPath, cidr, privateCidrs) -} - -func mergeVPCStatusCondition(ctx *context.Context, vpc *v1alpha1.VPC, newCondition *v1alpha1.Condition) bool { - matchedCondition := getExistingConditionOfType(newCondition.Type, vpc.Status.Conditions) - - if reflect.DeepEqual(matchedCondition, newCondition) { - log.V(2).Info("conditions already exist", "New Condition", newCondition, "Existing Condition", matchedCondition) - return false - } - - if matchedCondition != nil { - matchedCondition.Reason = newCondition.Reason - matchedCondition.Message = newCondition.Message - matchedCondition.Status = newCondition.Status - } else { - vpc.Status.Conditions = append(vpc.Status.Conditions, *newCondition) - } - return true -} - -func getExistingConditionOfType(conditionType v1alpha1.ConditionType, existingConditions []v1alpha1.Condition) *v1alpha1.Condition { - for i := range existingConditions { - if existingConditions[i].Type == v1alpha1.ConditionType(conditionType) { - return &existingConditions[i] - } - } - return nil -} - -// parse org id and project id from nsxtProject path -// example /orgs/default/projects/nsx_operator_e2e_test -func nsxtProjectPathToId(path string) (string, string, error) { - parts := strings.Split(path, "/") - if len(parts) < 4 { - return "", "", errors.New("Invalid NSXT project path") - } - return parts[2], parts[len(parts)-1], nil -} - -func isDefaultNetworkConfigCR(vpcConfigCR v1alpha1.VPCNetworkConfiguration) bool { - annos := vpcConfigCR.GetAnnotations() - val, exist := annos[types.AnnotationDefaultNetworkConfig] - if exist { - boolVar, err := strconv.ParseBool(val) - if err != nil { - log.Error(err, "failed to parse annotation to check default NetworkConfig", "Annotation", annos[types.AnnotationDefaultNetworkConfig]) - return false - } - return boolVar - } - return false -} - -func buildNetworkConfigInfo(vpcConfigCR v1alpha1.VPCNetworkConfiguration) (*types.VPCNetworkConfigInfo, error) { - org, project, err := nsxtProjectPathToId(vpcConfigCR.Spec.NSXTProject) - if err != nil { - log.Error(err, "failed to parse nsx-t project in network config", "Project Path", vpcConfigCR.Spec.NSXTProject) - return nil, err - } - - ninfo := &types.VPCNetworkConfigInfo{ - IsDefault: isDefaultNetworkConfigCR(vpcConfigCR), - Org: org, - Name: vpcConfigCR.Name, - DefaultGatewayPath: vpcConfigCR.Spec.DefaultGatewayPath, - EdgeClusterPath: vpcConfigCR.Spec.EdgeClusterPath, - NsxtProject: project, - ExternalIPv4Blocks: vpcConfigCR.Spec.ExternalIPv4Blocks, - PrivateIPv4CIDRs: vpcConfigCR.Spec.PrivateIPv4CIDRs, - DefaultIPv4SubnetSize: vpcConfigCR.Spec.DefaultIPv4SubnetSize, - DefaultSubnetAccessMode: vpcConfigCR.Spec.DefaultSubnetAccessMode, - ShortID: vpcConfigCR.Spec.ShortID, - } - return ninfo, nil -} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 5f1886405..613d04216 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -1,17 +1,22 @@ package logger import ( - "flag" + "os" "time" "github.com/go-logr/logr" + "github.com/go-logr/zapr" "go.uber.org/zap" "go.uber.org/zap/zapcore" logf "sigs.k8s.io/controller-runtime/pkg/log" - zapcr "sigs.k8s.io/controller-runtime/pkg/log/zap" ) -const logTmFmtWithMS = "2006-01-02 15:04:05.000" +const ( + logTmFmtWithMS = "2006-01-02 15:04:05.000" + // ANSI escape codes for coloring + colorReset = "\033[0m" + colorYellow = "\033[33m" +) var ( Log logr.Logger @@ -19,7 +24,7 @@ var ( enc.AppendString(t.Format(logTmFmtWithMS)) } customCallerEncoder = func(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString(caller.TrimmedPath()) + enc.AppendString(colorYellow + caller.TrimmedPath() + colorReset) } ) @@ -27,6 +32,10 @@ func init() { Log = logf.Log.WithName("nsx-operator") } +func InitLog(log *logr.Logger) { + Log = *log +} + // If debug set in configmap, set log level to 1. // If loglevel set in command line and greater than debug log level, set it to command line level. func getLogLevel(cfDebug bool, cfLogLevel int) int { @@ -42,6 +51,7 @@ func getLogLevel(cfDebug bool, cfLogLevel int) int { } func ZapLogger(cfDebug bool, cfLogLevel int) logr.Logger { + logLevel := getLogLevel(cfDebug, cfLogLevel) encoderConf := zapcore.EncoderConfig{ CallerKey: "caller_line", LevelKey: "level_name", @@ -55,24 +65,14 @@ func ZapLogger(cfDebug bool, cfLogLevel int) logr.Logger { EncodeDuration: zapcore.SecondsDurationEncoder, EncodeName: zapcore.FullNameEncoder, } + core := zapcore.NewCore( + zapcore.NewConsoleEncoder(encoderConf), + zapcore.AddSync(zapcore.Lock(os.Stdout)), + zapcore.Level(-1*logLevel), + ) + zapLogger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(0)) - opts := zapcr.Options{ - Development: true, - Level: zap.NewAtomicLevelAt(zap.InfoLevel), - Encoder: zapcore.NewConsoleEncoder(encoderConf), - StacktraceLevel: zap.FatalLevel, - } - opts.BindFlags(flag.CommandLine) - - // In level.go of zapcore, higher levels are more important. - // However, in logr.go, a higher verbosity level means a log message is less important. - // So we need to reverse the order of the levels. - logLevel := getLogLevel(cfDebug, cfLogLevel) - opts.Level = zapcore.Level(-1 * logLevel) - opts.ZapOpts = append(opts.ZapOpts, zap.AddCaller(), zap.AddCallerSkip(0)) - if logLevel > 0 { - opts.StacktraceLevel = zap.ErrorLevel - } + defer zapLogger.Sync() - return zapcr.New(zapcr.UseFlagOptions(&opts)) + return zapr.NewLogger(zapLogger) } diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 748a08fae..b4c8088a9 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -24,7 +24,7 @@ const ( ScrapeTimeout = 30 ) -var log = logger.Log +var log = &logger.Log var ( NSXOperatorHealthStats = prometheus.NewGauge( diff --git a/pkg/nsx/auth/jwt/JWTtokenprovider.go b/pkg/nsx/auth/jwt/JWTtokenprovider.go index bea9536f2..bd82f999b 100644 --- a/pkg/nsx/auth/jwt/JWTtokenprovider.go +++ b/pkg/nsx/auth/jwt/JWTtokenprovider.go @@ -17,7 +17,7 @@ const ( ) var ( - log = logger.Log + log = &logger.Log ) type JWTTokenProvider struct { diff --git a/pkg/nsx/client.go b/pkg/nsx/client.go index 1c9512d99..3af7aa23f 100644 --- a/pkg/nsx/client.go +++ b/pkg/nsx/client.go @@ -15,14 +15,18 @@ import ( mpsearch "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/search" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/trust_management" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/trust_management/principal_identities" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/domains" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/domains/security_policies" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/shares" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/sites/enforcement_points" - projects "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects" - infra "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/infra" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects" + project_infra "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/infra" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/infra/realized_state" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/transit_gateways" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/vpcs" - nat "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/vpcs/nat" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/vpcs/nat" vpc_sp "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/vpcs/security_policies" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/vpcs/subnets" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs/projects/vpcs/subnets/ip_pools" @@ -41,15 +45,14 @@ const ( ServiceAccountRestore ServiceAccountCertRotation StaticRoute - VpcAviRule AllFeatures ) -var FeaturesName = [AllFeatures]string{"VPC", "SECURITY_POLICY", "NSX_SERVICE_ACCOUNT", "NSX_SERVICE_ACCOUNT_RESTORE", "NSX_SERVICE_ACCOUNT_CERT_ROTATION", "STATIC_ROUTE", "VPC_AVI_RULE"} +var FeaturesName = [AllFeatures]string{"VPC", "SECURITY_POLICY", "NSX_SERVICE_ACCOUNT", "NSX_SERVICE_ACCOUNT_RESTORE", "NSX_SERVICE_ACCOUNT_CERT_ROTATION", "STATIC_ROUTE"} type Client struct { NsxConfig *config.NSXOperatorConfig - RestConnector *client.RestConnector + RestConnector client.Connector Cluster *Cluster QueryClient search.QueryClient @@ -71,19 +74,31 @@ type Client struct { VPCSecurityClient vpcs.SecurityPoliciesClient VPCRuleClient vpc_sp.RulesClient - OrgRootClient nsx_policy.OrgRootClient - ProjectInfraClient projects.InfraClient - VPCClient projects.VpcsClient - IPBlockClient infra.IpBlocksClient - StaticRouteClient vpcs.StaticRoutesClient - NATRuleClient nat.NatRulesClient - VpcGroupClient vpcs.GroupsClient - PortClient subnets.PortsClient - PortStateClient ports.StateClient - IPPoolClient subnets.IpPoolsClient - IPAllocationClient ip_pools.IpAllocationsClient - SubnetsClient vpcs.SubnetsClient - RealizedStateClient realized_state.RealizedEntitiesClient + OrgRootClient nsx_policy.OrgRootClient + ProjectInfraClient projects.InfraClient + VPCClient projects.VpcsClient + VPCConnectivityProfilesClient projects.VpcConnectivityProfilesClient + IPBlockClient project_infra.IpBlocksClient + StaticRouteClient vpcs.StaticRoutesClient + NATRuleClient nat.NatRulesClient + VpcGroupClient vpcs.GroupsClient + PortClient subnets.PortsClient + PortStateClient ports.StateClient + IPPoolClient subnets.IpPoolsClient + IPAllocationClient ip_pools.IpAllocationsClient + SubnetsClient vpcs.SubnetsClient + RealizedStateClient realized_state.RealizedEntitiesClient + IPAddressAllocationClient vpcs.IpAddressAllocationsClient + VPCLBSClient vpcs.VpcLbsClient + ProjectClient orgs.ProjectsClient + TransitGatewayClient projects.TransitGatewaysClient + TransitGatewayAttachmentClient transit_gateways.AttachmentsClient + CertificateClient infra.CertificatesClient + ShareClient infra.SharesClient + SharedResourceClient shares.ResourcesClient + LbAppProfileClient infra.LbAppProfilesClient + LbPersistenceProfilesClient infra.LbPersistenceProfilesClient + LbMonitorProfilesClient infra.LbMonitorProfilesClient NSXChecker NSXHealthChecker NSXVerChecker NSXVersionChecker @@ -116,7 +131,7 @@ func (ck *NSXHealthChecker) CheckNSXHealth(req *http.Request) error { } } -func restConnector(c *Cluster) *client.RestConnector { +func restConnector(c *Cluster) client.Connector { connector, _ := c.NewRestConnector() return connector } @@ -151,8 +166,10 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { orgRootClient := nsx_policy.NewOrgRootClient(restConnector(cluster)) projectInfraClient := projects.NewInfraClient(restConnector(cluster)) + projectClient := orgs.NewProjectsClient(restConnector(cluster)) vpcClient := projects.NewVpcsClient(restConnector(cluster)) - ipBlockClient := infra.NewIpBlocksClient(restConnector(cluster)) + vpcConnectivityProfilesClient := projects.NewVpcConnectivityProfilesClient(restConnector(cluster)) + ipBlockClient := project_infra.NewIpBlocksClient(restConnector(cluster)) staticRouteClient := vpcs.NewStaticRoutesClient(restConnector(cluster)) natRulesClient := nat.NewNatRulesClient(restConnector(cluster)) vpcGroupClient := vpcs.NewGroupsClient(restConnector(cluster)) @@ -163,10 +180,15 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { subnetsClient := vpcs.NewSubnetsClient(restConnector(cluster)) subnetStatusClient := subnets.NewStatusClient(restConnector(cluster)) realizedStateClient := realized_state.NewRealizedEntitiesClient(restConnector(cluster)) + ipAddressAllocationClient := vpcs.NewIpAddressAllocationsClient(restConnector(cluster)) + vpcLBSClient := vpcs.NewVpcLbsClient(restConnector(cluster)) vpcSecurityClient := vpcs.NewSecurityPoliciesClient(restConnector(cluster)) vpcRuleClient := vpc_sp.NewRulesClient(restConnector(cluster)) + transitGatewayClient := projects.NewTransitGatewaysClient(restConnector(cluster)) + transitGatewayAttachmentClient := transit_gateways.NewAttachmentsClient(restConnector(cluster)) + nsxChecker := &NSXHealthChecker{ cluster: cluster, } @@ -192,25 +214,30 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { PrincipalIdentitiesClient: principalIdentitiesClient, WithCertificateClient: withCertificateClient, - OrgRootClient: orgRootClient, - ProjectInfraClient: projectInfraClient, - VPCClient: vpcClient, - IPBlockClient: ipBlockClient, - StaticRouteClient: staticRouteClient, - NATRuleClient: natRulesClient, - VpcGroupClient: vpcGroupClient, - PortClient: portClient, - PortStateClient: portStateClient, - SubnetStatusClient: subnetStatusClient, - VPCSecurityClient: vpcSecurityClient, - VPCRuleClient: vpcRuleClient, - - NSXChecker: *nsxChecker, - NSXVerChecker: *nsxVersionChecker, - IPPoolClient: ipPoolClient, - IPAllocationClient: ipAllocationClient, - SubnetsClient: subnetsClient, - RealizedStateClient: realizedStateClient, + OrgRootClient: orgRootClient, + ProjectInfraClient: projectInfraClient, + VPCClient: vpcClient, + VPCConnectivityProfilesClient: vpcConnectivityProfilesClient, + IPBlockClient: ipBlockClient, + StaticRouteClient: staticRouteClient, + NATRuleClient: natRulesClient, + VpcGroupClient: vpcGroupClient, + PortClient: portClient, + PortStateClient: portStateClient, + SubnetStatusClient: subnetStatusClient, + VPCSecurityClient: vpcSecurityClient, + VPCRuleClient: vpcRuleClient, + VPCLBSClient: vpcLBSClient, + ProjectClient: projectClient, + NSXChecker: *nsxChecker, + NSXVerChecker: *nsxVersionChecker, + IPPoolClient: ipPoolClient, + IPAllocationClient: ipAllocationClient, + SubnetsClient: subnetsClient, + RealizedStateClient: realizedStateClient, + IPAddressAllocationClient: ipAddressAllocationClient, + TransitGatewayClient: transitGatewayClient, + TransitGatewayAttachmentClient: transitGatewayAttachmentClient, } // NSX version check will be restarted during SecurityPolicy reconcile // So, it's unnecessary to exit even if failed in the first time @@ -226,10 +253,6 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { err := errors.New("NSXServiceAccountRestore feature support check failed") log.Error(err, "initial NSX version check for NSXServiceAccountRestore got error") } - if !nsxClient.NSXCheckVersion(VpcAviRule) { - err := errors.New("VpcAviRule feature support check failed") - log.Error(err, "initial NSX version check for VpcAviRule got error") - } if !nsxClient.NSXCheckVersion(ServiceAccountCertRotation) { err := errors.New("ServiceAccountCertRotation feature support check failed") log.Error(err, "initial NSX version check for ServiceAccountCertRotation got error") diff --git a/pkg/nsx/cluster.go b/pkg/nsx/cluster.go index ed916f0df..4ef866d4c 100644 --- a/pkg/nsx/cluster.go +++ b/pkg/nsx/cluster.go @@ -63,7 +63,7 @@ type NsxVersion struct { var ( jarCache = NewJar() nsxVersion = &NsxVersion{} - log = logger.Log + log = &logger.Log ) // NewCluster creates a cluster based on nsx Config. @@ -156,16 +156,17 @@ func (cluster *Cluster) CreateServerUrl(host string, scheme string) string { } else { serverUrl = fmt.Sprintf("%s://%s", scheme, host) } - log.Info("create serverUrl", "serverUrl", serverUrl) + log.V(1).Info("create serverUrl", "serverUrl", serverUrl) return serverUrl } // NewRestConnector creates a RestConnector used for SDK client. // HeaderConfig is used to use http header for request, it could be ignored if no extra header needed. -func (cluster *Cluster) NewRestConnector() (*policyclient.RestConnector, *HeaderConfig) { +func (cluster *Cluster) NewRestConnector() (policyclient.Connector, *HeaderConfig) { nsxtUrl := cluster.CreateServerUrl(cluster.endpoints[0].Host(), cluster.endpoints[0].Scheme()) - connector := policyclient.NewRestConnector(nsxtUrl, *cluster.client) + connector := policyclient.NewConnector(nsxtUrl, policyclient.UsingRest(nil), policyclient.WithHttpClient(cluster.client)) header := CreateHeaderConfig(false, false, cluster.config.AllowOverwriteHeader) + connector.NewExecutionContext() return connector, header } @@ -433,9 +434,6 @@ func (nsxVersion *NsxVersion) featureSupported(feature int) bool { case ServiceAccountCertRotation: minVersion = nsx413Version validFeature = true - case VpcAviRule: - minVersion = nsx411Version - validFeature = true } if validFeature { diff --git a/pkg/nsx/ratelimiter/ratelimiter.go b/pkg/nsx/ratelimiter/ratelimiter.go index e70c5edc2..1bc92fe54 100644 --- a/pkg/nsx/ratelimiter/ratelimiter.go +++ b/pkg/nsx/ratelimiter/ratelimiter.go @@ -16,7 +16,7 @@ import ( // APIReduceRateCodes is http status code set which will trigger rate limiter adjust. var ( APIReduceRateCodes = [2]int{429, 503} - log = logger.Log + log = &logger.Log ) const ( diff --git a/pkg/nsx/services/common/builder_test.go b/pkg/nsx/services/common/builder_test.go index 5c222fcec..9a00f4d03 100644 --- a/pkg/nsx/services/common/builder_test.go +++ b/pkg/nsx/services/common/builder_test.go @@ -135,13 +135,12 @@ func TestParseVPCResourcePath(t *testing.T) { nsxResourcePath: "/orgs/org1/projects/proj1/vpcs/vpc1/subnets/subnet1/ports/port1", }, want: VPCResourceInfo{ - OrgID: "org1", - ProjectID: "proj1", - VPCID: "vpc1", - ParentID: "subnet1", - ID: "port1", - PrivateIpv4Blocks: nil, - ExternalIPv4Blocks: nil, + OrgID: "org1", + ProjectID: "proj1", + VPCID: "vpc1", + ParentID: "subnet1", + ID: "port1", + PrivateIpv4Blocks: nil, }, wantErr: false, }, @@ -151,13 +150,12 @@ func TestParseVPCResourcePath(t *testing.T) { nsxResourcePath: "/orgs/org1/projects/proj1/vpcs/vpc1", }, want: VPCResourceInfo{ - OrgID: "org1", - ProjectID: "proj1", - VPCID: "vpc1", - ParentID: "proj1", - ID: "vpc1", - PrivateIpv4Blocks: nil, - ExternalIPv4Blocks: nil, + OrgID: "org1", + ProjectID: "proj1", + VPCID: "vpc1", + ParentID: "proj1", + ID: "vpc1", + PrivateIpv4Blocks: nil, }, wantErr: false, }, diff --git a/pkg/nsx/services/common/compare.go b/pkg/nsx/services/common/compare.go index f8b259355..bd743b2b9 100644 --- a/pkg/nsx/services/common/compare.go +++ b/pkg/nsx/services/common/compare.go @@ -7,7 +7,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/logger" ) -var log = logger.Log +var log = &logger.Log type Comparable interface { Key() string diff --git a/pkg/nsx/services/common/services.go b/pkg/nsx/services/common/services.go index 19f0d7255..5829be053 100644 --- a/pkg/nsx/services/common/services.go +++ b/pkg/nsx/services/common/services.go @@ -11,6 +11,8 @@ import ( // calling method that should not be exposed. type VPCServiceProvider interface { RegisterNamespaceNetworkconfigBinding(ns string, ncCRName string) + GetNamespacesByNetworkconfigName(nc string) []string + RegisterVPCNetworkConfig(ncCRName string, info VPCNetworkConfigInfo) UnRegisterNamespaceNetworkconfigBinding(ns string) GetVPCNetworkConfig(ncCRName string) (VPCNetworkConfigInfo, bool) ValidateNetworkConfig(nc VPCNetworkConfigInfo) bool diff --git a/pkg/nsx/services/common/services_mock.go b/pkg/nsx/services/common/services_mock.go index 0f74fbec5..abe8bd57a 100644 --- a/pkg/nsx/services/common/services_mock.go +++ b/pkg/nsx/services/common/services_mock.go @@ -8,6 +8,13 @@ type MockVPCServiceProvider struct { mock.Mock } +func (m *MockVPCServiceProvider) GetNamespacesByNetworkconfigName(nc string) []string { + return nil +} + +func (m *MockVPCServiceProvider) RegisterVPCNetworkConfig(ncCRName string, info VPCNetworkConfigInfo) { +} + func (m *MockVPCServiceProvider) RegisterNamespaceNetworkconfigBinding(ns string, ncCRName string) { m.Called(ns, ncCRName) } diff --git a/pkg/nsx/services/common/store.go b/pkg/nsx/services/common/store.go index 692778e1a..0f149d353 100644 --- a/pkg/nsx/services/common/store.go +++ b/pkg/nsx/services/common/store.go @@ -7,7 +7,7 @@ import ( "strings" "sync" - vapierrors "github.com/vmware/vsphere-automation-sdk-go/lib/vapi/std/errors" + apierrors "github.com/vmware/vsphere-automation-sdk-go/lib/vapi/std/errors" "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" "github.com/vmware/vsphere-automation-sdk-go/runtime/data" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" @@ -51,6 +51,9 @@ func (resourceStore *ResourceStore) TransResourceToStore(entity *data.StructValu } } objAddr := nsxutil.CasttoPointer(obj) + if objAddr == nil { + return fmt.Errorf("failed to cast to pointer") + } err2 := resourceStore.Add(objAddr) if err2 != nil { return err2 @@ -101,22 +104,13 @@ func (resourceStore *ResourceStore) IsPolicyAPI() bool { } func TransError(err error) error { - switch err.(type) { - case vapierrors.ServiceUnavailable: - vApiError, _ := err.(vapierrors.ServiceUnavailable) - if vApiError.Data == nil { - return err - } - dataError, errs := NewConverter().ConvertToGolang(vApiError.Data, model.ApiErrorBindingType()) - if len(errs) > 0 { - return err - } - apiError := dataError.(model.ApiError) - if *apiError.ErrorCode == int64(60576) { + apierror, errortype := nsxutil.DumpAPIError(err) + if apierror != nil { + log.Info("translate error", "apierror", apierror, "error type", errortype) + if *errortype == apierrors.ErrorType_SERVICE_UNAVAILABLE && *apierror.ErrorCode == int64(60576) || + *errortype == apierrors.ErrorType_INVALID_REQUEST && *apierror.ErrorCode == int64(255) { return nsxutil.PageMaxError{Desc: "page max overflow"} } - default: - return err } return err } @@ -137,33 +131,34 @@ type Filter func(interface{}) *data.StructValue func (service *Service) SearchResource(resourceTypeValue string, queryParam string, store Store, filter Filter) (uint64, error) { var cursor *string + pagesize := PageSize count := uint64(0) for { var err error var results []*data.StructValue var resultCount *int64 if store.IsPolicyAPI() { - response, searchEerr := service.NSXClient.QueryClient.List(queryParam, cursor, nil, Int64(PageSize), nil, nil) + response, searchEerr := service.NSXClient.QueryClient.List(queryParam, cursor, nil, &pagesize, nil, nil) results = response.Results cursor = response.Cursor resultCount = response.ResultCount err = searchEerr } else { - response, searchEerr := service.NSXClient.MPQueryClient.List(queryParam, cursor, nil, Int64(PageSize), nil, nil) + response, searchEerr := service.NSXClient.MPQueryClient.List(queryParam, cursor, nil, &pagesize, nil, nil) results = response.Results cursor = response.Cursor resultCount = response.ResultCount err = searchEerr } - - err = TransError(err) - if _, ok := err.(nsxutil.PageMaxError); ok == true { - DecrementPageSize(Int64(PageSize)) - continue - } if err != nil { + err = TransError(err) + if _, ok := err.(nsxutil.PageMaxError); ok == true { + DecrementPageSize(&pagesize) + continue + } return count, err } + for _, entity := range results { if filter != nil { entity = filter(entity) @@ -197,19 +192,25 @@ func (service *Service) PopulateResourcetoStore(wg *sync.WaitGroup, fatalErrors // InitializeCommonStore is the common method used by InitializeResourceStore and InitializeVPCResourceStore func (service *Service) InitializeCommonStore(wg *sync.WaitGroup, fatalErrors chan error, org string, project string, resourceTypeValue string, tags []model.Tag, store Store) { - tagScopeClusterKey := strings.Replace(TagScopeCluster, "/", "\\/", -1) - tagScopeClusterValue := strings.Replace(service.NSXClient.NsxConfig.Cluster, ":", "\\:", -1) - tagParam := fmt.Sprintf("tags.scope:%s AND tags.tag:%s", tagScopeClusterKey, tagScopeClusterValue) + var tagParams []string + // Check for specific tag scopes + if !containsTagScope(tags, TagScopeCluster, TagScopeNCPCluster) { + tagParams = append(tagParams, formatTagParamScope("tags.scope", TagScopeCluster)) + tagParams = append(tagParams, formatTagParamTag("tags.tag", service.NSXClient.NsxConfig.Cluster)) + } for _, tag := range tags { - tagKey := strings.Replace(*tag.Scope, "/", "\\/", -1) - tagParam += fmt.Sprintf(" AND tags.scope:%s ", tagKey) - if tag.Tag != nil { - tagValue := strings.Replace(*tag.Tag, ":", "\\:", -1) - tagParam += fmt.Sprintf(" AND tags.tag:%s ", tagValue) + if tag.Scope != nil { + tagParams = append(tagParams, formatTagParamScope("tags.scope", *tag.Scope)) + if tag.Tag != nil { + tagParams = append(tagParams, formatTagParamTag("tags.tag", *tag.Tag)) + } } } + // Join all tag parameters with "AND" + tagParam := strings.Join(tagParams, " AND ") + resourceParam := fmt.Sprintf("%s:%s", ResourceType, resourceTypeValue) queryParam := resourceParam + " AND " + tagParam @@ -220,6 +221,31 @@ func (service *Service) InitializeCommonStore(wg *sync.WaitGroup, fatalErrors ch pathUnescape, _ := url.PathUnescape("path%3A") queryParam += " AND " + pathUnescape + path } - queryParam += " AND marked_for_delete:false" + if store.IsPolicyAPI() { + queryParam += " AND marked_for_delete:false" + } service.PopulateResourcetoStore(wg, fatalErrors, resourceTypeValue, queryParam, store, nil) } + +// Helper function to check if any tag has the specified scopes +func containsTagScope(tags []model.Tag, scopes ...string) bool { + for _, tag := range tags { + for _, scope := range scopes { + if tag.Scope != nil && *tag.Scope == scope { + return true + } + } + } + return false +} + +// Helper function to format tag parameters +func formatTagParamScope(paramType, value string) string { + valueEscaped := strings.Replace(value, "/", "\\/", -1) + return fmt.Sprintf("%s:%s", paramType, valueEscaped) +} + +func formatTagParamTag(paramType, value string) string { + valueEscaped := strings.Replace(value, ":", "\\:", -1) + return fmt.Sprintf("%s:%s", paramType, valueEscaped) +} diff --git a/pkg/nsx/services/common/types.go b/pkg/nsx/services/common/types.go index c563aceb6..f38967eef 100644 --- a/pkg/nsx/services/common/types.go +++ b/pkg/nsx/services/common/types.go @@ -28,6 +28,7 @@ const ( TagScopeNCPVIFProjectUID string = "ncp/vif_project_uid" TagScopeNCPPod string = "ncp/pod" TagScopeNCPVNETInterface string = "ncp/vnet_interface" + TagScopeCreatedFor string = "nsx-op/created_for" TagScopeVersion string = "nsx-op/version" TagScopeCluster string = "nsx-op/cluster" TagScopeNamespace string = "nsx-op/namespace" @@ -48,24 +49,27 @@ const ( TagScopeNSXServiceAccountCRUID string = "nsx-op/nsx_service_account_uid" TagScopeNSXProjectID string = "nsx-op/nsx_project_id" TagScopeProjectGroupShared string = "nsx-op/is_nsx_project_shared" - TagScopeVPCCRName string = "nsx-op/vpc_name" - TagScopeVPCCRUID string = "nsx-op/vpc_uid" TagScopeSubnetPortCRName string = "nsx-op/subnetport_name" TagScopeSubnetPortCRUID string = "nsx-op/subnetport_uid" TagScopeIPPoolCRName string = "nsx-op/ippool_name" TagScopeIPPoolCRUID string = "nsx-op/ippool_uid" TagScopeIPPoolCRType string = "nsx-op/ippool_type" + TagScopeIPAddressAllocationCRName string = "nsx-op/ipaddressallocation_name" + TagScopeIPAddressAllocationCRUID string = "nsx-op/ipaddressallocation_uid" TagScopeIPSubnetName string = "nsx-op/ipsubnet_name" TagScopeVMNamespaceUID string = "nsx-op/vm_namespace_uid" TagScopeVMNamespace string = "nsx-op/vm_namespace" + TagScopeVPCManagedBy string = "nsx/managed-by" + AutoCreatedVPCTagValue string = "nsx-op" LabelDefaultSubnetSet string = "nsxoperator.vmware.com/default-subnetset-for" LabelDefaultVMSubnetSet string = "VirtualMachine" LabelDefaultPodSubnetSet string = "Pod" - LabelLbIngressIpMode string = "tanzu.vmware.com/ingress-ip-mode" + LabelLbIngressIpMode string = "nsx.vmware.com/ingress-ip-mode" LabelLbIngressIpModeVipValue string = "vip" LabelLbIngressIpModeProxyValue string = "proxy" DefaultPodSubnetSet string = "pod-default" DefaultVMSubnetSet string = "vm-default" + SystemVPCNetworkConfigurationName string = "system" TagScopeSubnetCRUID string = "nsx-op/subnet_uid" TagScopeSubnetCRName string = "nsx-op/subnet_name" TagScopeSubnetSetCRName string = "nsx-op/subnetset_name" @@ -74,8 +78,9 @@ const ( TagValueGroupSource string = "source" TagValueGroupDestination string = "destination" TagValueGroupAvi string = "avi" + TagValueSLB string = "SLB" AnnotationVPCNetworkConfig string = "nsx.vmware.com/vpc_network_config" - AnnotationVPCName string = "nsx.vmware.com/vpc_name" + AnnotationSharedVPCNamespace string = "nsx.vmware.com/shared_vpc_namespace" AnnotationDefaultNetworkConfig string = "nsx.vmware.com/default" AnnotationAttachmentRef string = "nsx.vmware.com/attachment_ref" AnnotationPodMAC string = "nsx.vmware.com/mac" @@ -86,24 +91,27 @@ const ( ValueMinorVersion string = "0" ValuePatchVersion string = "0" - GCInterval = 60 * time.Second - RealizeTimeout = 2 * time.Minute - RealizeMaxRetries = 3 - IPPoolFinalizerName = "ippool.nsx.vmware.com/finalizer" - DefaultSNATID = "DEFAULT" - AVISubnetLBID = "_AVI_SUBNET--LB" - IPPoolTypePublic = "Public" - IPPoolTypePrivate = "Private" - - SecurityPolicyFinalizerName = "securitypolicy.nsx.vmware.com/finalizer" - NetworkPolicyFinalizerName = "networkpolicy.nsx.vmware.com/finalizer" - StaticRouteFinalizerName = "staticroute.nsx.vmware.com/finalizer" + GCInterval = 60 * time.Second + RealizeTimeout = 2 * time.Minute + RealizeMaxRetries = 3 + DefaultSNATID = "DEFAULT" + AVISubnetLBID = "_services" + IPPoolTypePublic = "Public" + IPPoolTypePrivate = "Private" + NSXServiceAccountFinalizerName = "nsxserviceaccount.nsx.vmware.com/finalizer" - SubnetFinalizerName = "subnet.nsx.vmware.com/finalizer" - SubnetSetFinalizerName = "subnetset.nsx.vmware.com/finalizer" - SubnetPortFinalizerName = "subnetport.nsx.vmware.com/finalizer" - VPCFinalizerName = "vpc.nsx.vmware.com/finalizer" - PodFinalizerName = "pod.nsx.vmware.com/finalizer" + T1SecurityPolicyFinalizerName = "securitypolicy.nsx.vmware.com/finalizer" + + SecurityPolicyFinalizerName = "securitypolicy.crd.nsx.vmware.com/finalizer" + NetworkPolicyFinalizerName = "networkpolicy.crd.nsx.vmware.com/finalizer" + StaticRouteFinalizerName = "staticroute.crd.nsx.vmware.com/finalizer" + SubnetFinalizerName = "subnet.crd.nsx.vmware.com/finalizer" + SubnetSetFinalizerName = "subnetset.crd.nsx.vmware.com/finalizer" + SubnetPortFinalizerName = "subnetport.crd.nsx.vmware.com/finalizer" + NetworkInfoFinalizerName = "networkinfo.crd.nsx.vmware.com/finalizer" + PodFinalizerName = "pod.crd.nsx.vmware.com/finalizer" + IPPoolFinalizerName = "ippool.crd.nsx.vmware.com/finalizer" + IPAddressAllocationFinalizerName = "ipaddressallocation.crd.nsx.vmware.com/finalizer" IndexKeySubnetID = "IndexKeySubnetID" IndexKeyPathPath = "Path" @@ -132,37 +140,53 @@ var ( ) var ( - ResourceType = "resource_type" - ResourceTypeInfra = "Infra" - ResourceTypeDomain = "Domain" - ResourceTypeSecurityPolicy = "SecurityPolicy" - ResourceTypeNetworkPolicy = "NetworkPolicy" - ResourceTypeGroup = "Group" - ResourceTypeRule = "Rule" - ResourceTypeIPBlock = "IpAddressBlock" - ResourceTypeOrgRoot = "OrgRoot" - ResourceTypeOrg = "Org" - ResourceTypeProject = "Project" - ResourceTypeVpc = "Vpc" - ResourceTypeSubnetPort = "VpcSubnetPort" - ResourceTypeVirtualMachine = "VirtualMachine" - ResourceTypeShare = "Share" - ResourceTypeSharedResource = "SharedResource" - ResourceTypeChildSharedResource = "ChildSharedResource" - ResourceTypeChildShare = "ChildShare" - ResourceTypeChildRule = "ChildRule" - ResourceTypeChildGroup = "ChildGroup" - ResourceTypeChildSecurityPolicy = "ChildSecurityPolicy" - ResourceTypeChildResourceReference = "ChildResourceReference" + ResourceType = "resource_type" + ResourceTypeInfra = "Infra" + ResourceTypeDomain = "Domain" + ResourceTypeSecurityPolicy = "SecurityPolicy" + ResourceTypeNetworkPolicy = "NetworkPolicy" + ResourceTypeGroup = "Group" + ResourceTypeRule = "Rule" + ResourceTypeIPBlock = "IpAddressBlock" + ResourceTypeOrgRoot = "OrgRoot" + ResourceTypeOrg = "Org" + ResourceTypeProject = "Project" + ResourceTypeVpc = "Vpc" + ResourceTypeSubnetPort = "VpcSubnetPort" + ResourceTypeVirtualMachine = "VirtualMachine" + ResourceTypeLBService = "LBService" + ResourceTypeShare = "Share" + ResourceTypeSharedResource = "SharedResource" + ResourceTypeChildSharedResource = "ChildSharedResource" + ResourceTypeChildShare = "ChildShare" + ResourceTypeChildRule = "ChildRule" + ResourceTypeChildGroup = "ChildGroup" + ResourceTypeChildSecurityPolicy = "ChildSecurityPolicy" + ResourceTypeChildResourceReference = "ChildResourceReference" + ResourceTypeTlsCertificate = "TlsCertificate" + ResourceTypeLBHttpProfile = "LBHttpProfile" + ResourceTypeLBFastTcpProfile = "LBFastTcpProfile" + ResourceTypeLBFastUdpProfile = "LBFastUdpProfile" + ResourceTypeLBCookiePersistenceProfile = "LBCookiePersistenceProfile" + ResourceTypeLBSourceIpPersistenceProfile = "LBSourceIpPersistenceProfile" + ResourceTypeLBHttpMonitorProfile = "LBHttpMonitorProfile" + ResourceTypeLBTcpMonitorProfile = "LBTcpMonitorProfile" // ResourceTypeClusterControlPlane is used by NSXServiceAccountController ResourceTypeClusterControlPlane = "clustercontrolplane" // ResourceTypePrincipalIdentity is used by NSXServiceAccountController, and it is MP resource type. - ResourceTypePrincipalIdentity = "principalidentity" - ResourceTypeSubnet = "VpcSubnet" - ResourceTypeIPPool = "IpAddressPool" - ResourceTypeIPPoolBlockSubnet = "IpAddressPoolBlockSubnet" - ResourceTypeNode = "HostTransportNode" + ResourceTypePrincipalIdentity = "principalidentity" + ResourceTypeSubnet = "VpcSubnet" + ResourceTypeIPPool = "IpAddressPool" + ResourceTypeIPAddressAllocation = "VpcIpAddressAllocation" + ResourceTypeIPPoolBlockSubnet = "IpAddressPoolBlockSubnet" + ResourceTypeNode = "HostTransportNode" + + // Reasons for verification of gateway connection in day0 + ReasonEdgeMissingInProject = "EdgeMissingInProject" + ReasonDistributedGatewayConnectionNotSupported = "DistributedGatewayConnectionNotSupported" + ReasonGatewayConnectionNotSet = "GatewayConnectionNotSet" + ReasonNoExternalIPBlocksInVPCConnectivityProfile = "ExternalIPBlockMissingInProfile" ) type Service struct { @@ -190,22 +214,18 @@ type VPCResourceInfo struct { // ID=port1, ParentID=s1; // 2. For the subnet with path /orgs/o1/projects/p1/vpcs/v1/subnets/s1, // ID=s1, ParentID=v1 (ParentID==VPCID). - ID string - ParentID string - PrivateIpv4Blocks []string - ExternalIPv4Blocks []string + ID string + ParentID string + PrivateIpv4Blocks []string } type VPCNetworkConfigInfo struct { - IsDefault bool - Org string - Name string - DefaultGatewayPath string - EdgeClusterPath string - NsxtProject string - ExternalIPv4Blocks []string - PrivateIPv4CIDRs []string - DefaultIPv4SubnetSize int - DefaultSubnetAccessMode string - ShortID string + IsDefault bool + Org string + Name string + VPCConnectivityProfile string + NSXProject string + PrivateIPs []string + DefaultSubnetSize int + VPCPath string } diff --git a/pkg/nsx/services/common/wrap.go b/pkg/nsx/services/common/wrap.go new file mode 100644 index 000000000..a2c96d3a0 --- /dev/null +++ b/pkg/nsx/services/common/wrap.go @@ -0,0 +1,84 @@ +package common + +import ( + "github.com/openlyinc/pointy" + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +// WrapInfra TODO(gran) refactor existing code in other package +func (service *Service) WrapInfra(children []*data.StructValue) (*model.Infra, error) { + // This is the outermost layer of the hierarchy infra client. + // It doesn't need ID field. + resourceType := ResourceTypeInfra + infraObj := model.Infra{ + Children: children, + ResourceType: &resourceType, + } + return &infraObj, nil +} + +func (service *Service) WrapOrgRoot(children []*data.StructValue) (*model.OrgRoot, error) { + resourceType := ResourceTypeOrgRoot + orgRootObj := model.OrgRoot{ + Children: children, + ResourceType: &resourceType, + } + return &orgRootObj, nil +} + +func (service *Service) WrapOrg(org string, children []*data.StructValue) ([]*data.StructValue, error) { + targetType := ResourceTypeOrg + return wrapChildResourceReference(targetType, org, children) +} + +func (service *Service) WrapProject(nsxtProject string, children []*data.StructValue) ([]*data.StructValue, error) { + targetType := ResourceTypeProject + return wrapChildResourceReference(targetType, nsxtProject, children) +} + +func wrapChildResourceReference(targetType, id string, children []*data.StructValue) ([]*data.StructValue, error) { + resourceType := ResourceTypeChildResourceReference + childProject := model.ChildResourceReference{ + Id: &id, + ResourceType: resourceType, + TargetType: &targetType, + Children: children, + } + dataValue, errors := NewConverter().ConvertToVapi(childProject, childProject.GetType__()) + if len(errors) > 0 { + return nil, errors[0] + } + return []*data.StructValue{dataValue.(*data.StructValue)}, nil + +} + +func (service *Service) WrapVPC(vpc *model.Vpc) ([]*data.StructValue, error) { + vpc.ResourceType = pointy.String(ResourceTypeVpc) + childVpc := model.ChildVpc{ + Id: vpc.Id, + MarkedForDelete: vpc.MarkedForDelete, + ResourceType: "ChildVpc", + Vpc: vpc, + } + dataValue, errs := NewConverter().ConvertToVapi(childVpc, childVpc.GetType__()) + if len(errs) > 0 { + return nil, errs[0] + } + return []*data.StructValue{dataValue.(*data.StructValue)}, nil +} + +func (service *Service) WrapLBS(lbs *model.LBService) ([]*data.StructValue, error) { + lbs.ResourceType = pointy.String(ResourceTypeLBService) + childLBService := model.ChildLBService{ + Id: lbs.Id, + MarkedForDelete: lbs.MarkedForDelete, + ResourceType: "ChildLBService", + LbService: lbs, + } + dataValue, errs := NewConverter().ConvertToVapi(childLBService, childLBService.GetType__()) + if len(errs) > 0 { + return nil, errs[0] + } + return []*data.StructValue{dataValue.(*data.StructValue)}, nil +} diff --git a/pkg/nsx/services/ipaddressallocation/builder.go b/pkg/nsx/services/ipaddressallocation/builder.go new file mode 100644 index 000000000..d1acc2e9b --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/builder.go @@ -0,0 +1,57 @@ +package ipaddressallocation + +import ( + "fmt" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/util" +) + +var ( + Int64 = common.Int64 + String = common.String +) + +const ( + IPADDRESSALLOCATIONPREFIX = "ipa" +) + +func convertIpAddressBlockVisibility(visibility v1alpha1.IPAddressVisibility) v1alpha1.IPAddressVisibility { + if visibility == v1alpha1.IPAddressVisibilityPrivateTGW { + return "PRIVATE_TGW" + } + return visibility +} + +func (service *IPAddressAllocationService) BuildIPAddressAllocation(IPAddressAllocation *v1alpha1.IPAddressAllocation) (*model.VpcIpAddressAllocation, error) { + VPCInfo := service.VPCService.ListVPCInfo(IPAddressAllocation.Namespace) + if len(VPCInfo) == 0 { + log.Error(nil, "failed to find VPCInfo for IPAddressAllocation CR", "IPAddressAllocation", IPAddressAllocation.Name, "namespace", IPAddressAllocation.Namespace) + return nil, fmt.Errorf("failed to find VPCInfo for IPAddressAllocation CR %s in namespace %s", IPAddressAllocation.Name, IPAddressAllocation.Namespace) + } + + ipAddressBlockVisibility := convertIpAddressBlockVisibility(IPAddressAllocation.Spec.IPAddressBlockVisibility) + ipAddressBlockVisibilityStr := util.ToUpper(string(ipAddressBlockVisibility)) + return &model.VpcIpAddressAllocation{ + Id: String(service.buildIPAddressAllocationID(IPAddressAllocation)), + DisplayName: String(service.buildIPAddressAllocationName(IPAddressAllocation)), + Tags: service.buildIPAddressAllocationTags(IPAddressAllocation), + IpAddressBlockVisibility: &ipAddressBlockVisibilityStr, + AllocationSize: Int64(int64(IPAddressAllocation.Spec.AllocationSize)), + }, nil +} + +func (service *IPAddressAllocationService) buildIPAddressAllocationID(IPAddressAllocation *v1alpha1.IPAddressAllocation) string { + return util.GenerateIDByObject(IPAddressAllocation) +} + +func (service *IPAddressAllocationService) buildIPAddressAllocationName(IPAddressAllocation *v1alpha1.IPAddressAllocation) string { + return util.GenerateTruncName(common.MaxNameLength, IPAddressAllocation.ObjectMeta.Name, "", "", "", service.NSXConfig.Cluster) +} + +func (service *IPAddressAllocationService) buildIPAddressAllocationTags(IPAddressAllocation *v1alpha1.IPAddressAllocation) []model.Tag { + return util.BuildBasicTags(service.NSXConfig.Cluster, IPAddressAllocation, "") +} diff --git a/pkg/nsx/services/ipaddressallocation/builder_test.go b/pkg/nsx/services/ipaddressallocation/builder_test.go new file mode 100644 index 000000000..2c8cd8884 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/builder_test.go @@ -0,0 +1,149 @@ +package ipaddressallocation + +import ( + "reflect" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/config" + mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" + mocks "github.com/vmware-tanzu/nsx-operator/pkg/mock/vpcclient" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +type fakeQueryClient struct { +} + +func (qIface *fakeQueryClient) List(_ string, _ *string, _ *string, _ *int64, _ *bool, _ *string) (model.SearchResponse, error) { + cursor := "2" + resultCount := int64(2) + return model.SearchResponse{ + Results: []*data.StructValue{{}}, + Cursor: &cursor, ResultCount: &resultCount, + }, nil +} + +func createService(t *testing.T) (*vpc.VPCService, *gomock.Controller, *mocks.MockVpcsClient) { + config2 := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) + + cluster, _ := nsx.NewCluster(config2) + rc, _ := cluster.NewRestConnector() + + mockCtrl := gomock.NewController(t) + mockVpcclient := mocks.NewMockVpcsClient(mockCtrl) + k8sClient := mock_client.NewMockClient(mockCtrl) + + vpcStore := &vpc.VPCStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeStaticRouteCRUID: indexFunc}), + BindingType: model.VpcBindingType(), + }} + + service := &vpc.VPCService{ + Service: common.Service{ + Client: k8sClient, + NSXClient: &nsx.Client{ + QueryClient: &fakeQueryClient{}, + VPCClient: mockVpcclient, + RestConnector: rc, + NsxConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "k8scl-one:test", + }, + }, + }, + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "k8scl-one:test", + }, + }, + }, + VpcStore: vpcStore, + VPCNetworkConfigStore: vpc.VPCNetworkInfoStore{ + VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, + }, + VPCNSNetworkConfigStore: vpc.VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: map[string]string{}, + }, + } + return service, mockCtrl, mockVpcclient +} + +func TestBuildIPAddressAllocation(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + vpcService, _, _ := createService(t) + ipAllocService := &IPAddressAllocationService{ + VPCService: vpcService, + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + EnforcementPoint: "vmc-enforcementpoint", + }, + CoeConfig: &config.CoeConfig{ + Cluster: "default", + }, + }, + }, + } + + t.Run("VPCInfo is empty", func(t *testing.T) { + ipAlloc := &v1alpha1.IPAddressAllocation{} + ipAlloc.Namespace = "default" + ipAlloc.Name = "test-ip-alloc" + ipAlloc.UID = "uid1" + + patch := gomonkey.ApplyMethod(reflect.TypeOf(ipAllocService.VPCService), "ListVPCInfo", func(_ *vpc.VPCService, _ string) []common.VPCResourceInfo { + return []common.VPCResourceInfo{} + }) + defer patch.Reset() + + result, err := ipAllocService.BuildIPAddressAllocation(ipAlloc) + assert.Nil(t, result) + assert.EqualError(t, err, "failed to find VPCInfo for IPAddressAllocation CR test-ip-alloc in namespace default") + }) + + t.Run("Success case", func(t *testing.T) { + ipAlloc := &v1alpha1.IPAddressAllocation{ + ObjectMeta: v1.ObjectMeta{ + Name: "test-ip-alloc", + Namespace: "default", + UID: "uid1", + }, + Spec: v1alpha1.IPAddressAllocationSpec{ + IPAddressBlockVisibility: v1alpha1.IPAddressVisibilityExternal, + AllocationSize: 10, + }, + } + patch := gomonkey.ApplyMethod(reflect.TypeOf(ipAllocService.VPCService), "ListVPCInfo", func(_ *vpc.VPCService, _ string) []common.VPCResourceInfo { + return []common.VPCResourceInfo{ + { + OrgID: "org1", + ProjectID: "proj1", + VPCID: "vpc1", + }, + } + }) + defer patch.Reset() + + result, err := ipAllocService.BuildIPAddressAllocation(ipAlloc) + assert.Nil(t, err) + assert.Equal(t, "test-ip-alloc-uid1", *result.Id) + assert.Equal(t, "default-test-ip-alloc", *result.DisplayName) + assert.Equal(t, int64(10), *result.AllocationSize) + assert.Equal(t, "EXTERNAL", *result.IpAddressBlockVisibility) + assert.Equal(t, 5, len(result.Tags)) + }) +} diff --git a/pkg/nsx/services/ipaddressallocation/compare.go b/pkg/nsx/services/ipaddressallocation/compare.go new file mode 100644 index 000000000..acec5441c --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/compare.go @@ -0,0 +1,35 @@ +package ipaddressallocation + +import ( + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +type ( + IpAddressAllocation model.VpcIpAddressAllocation +) + +type Comparable = common.Comparable + +func (ipa *IpAddressAllocation) Key() string { + return *ipa.Id +} + +func (ipa *IpAddressAllocation) Value() data.DataValue { + if ipa == nil { + return nil + } + s := &IpAddressAllocation{Id: ipa.Id, DisplayName: ipa.DisplayName, Tags: ipa.Tags, AllocationSize: ipa.AllocationSize, IpAddressBlockVisibility: ipa.IpAddressBlockVisibility} + dataValue, _ := ComparableToIpAddressAllocation(s).GetDataValue__() + return dataValue +} + +func IpAddressAllocationToComparable(iap *model.VpcIpAddressAllocation) Comparable { + return (*IpAddressAllocation)(iap) +} + +func ComparableToIpAddressAllocation(iap Comparable) *model.VpcIpAddressAllocation { + return (*model.VpcIpAddressAllocation)(iap.(*IpAddressAllocation)) +} diff --git a/pkg/nsx/services/ipaddressallocation/compare_test.go b/pkg/nsx/services/ipaddressallocation/compare_test.go new file mode 100644 index 000000000..7e18ba86b --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/compare_test.go @@ -0,0 +1,52 @@ +package ipaddressallocation + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func TestKey(t *testing.T) { + id := "test-id" + iap := &IpAddressAllocation{Id: &id} + assert.Equal(t, "test-id", iap.Key()) + + iapNil := &IpAddressAllocation{Id: nil} + assert.Panics(t, func() { iapNil.Key() }) +} + +func TestValue(t *testing.T) { + id := "test-id" + displayName := "test-display-name" + tags := []model.Tag{{Scope: String("scope"), Tag: String("tag")}} + iap := &IpAddressAllocation{Id: &id, DisplayName: &displayName, Tags: tags} + + dataValue := iap.Value() + expectedDataValue, _ := ComparableToIpAddressAllocation(iap).GetDataValue__() + + assert.Equal(t, expectedDataValue, dataValue) +} + +func TestIpAddressAllocationToComparable(t *testing.T) { + id := "test-id" + displayName := "test-display-name" + tags := []model.Tag{{Scope: String("scope"), Tag: String("tag")}} + vpcIap := &model.VpcIpAddressAllocation{Id: &id, DisplayName: &displayName, Tags: tags} + + comparable := IpAddressAllocationToComparable(vpcIap) + assert.IsType(t, &IpAddressAllocation{}, comparable) +} + +func TestComparableToIpAddressAllocation(t *testing.T) { + id := "test-id" + displayName := "test-display-name" + tags := []model.Tag{{Scope: String("scope"), Tag: String("tag")}} + iap := &IpAddressAllocation{Id: &id, DisplayName: &displayName, Tags: tags} + + vpcIap := ComparableToIpAddressAllocation(iap) + assert.IsType(t, &model.VpcIpAddressAllocation{}, vpcIap) + assert.Equal(t, id, *vpcIap.Id) + assert.Equal(t, displayName, *vpcIap.DisplayName) + assert.Equal(t, tags, vpcIap.Tags) +} diff --git a/pkg/nsx/services/ipaddressallocation/ipaddressallocation.go b/pkg/nsx/services/ipaddressallocation/ipaddressallocation.go new file mode 100644 index 000000000..0ae9675aa --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/ipaddressallocation.go @@ -0,0 +1,217 @@ +package ipaddressallocation + +import ( + "context" + "fmt" + "sync" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/logger" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" +) + +var ( + log = &logger.Log + MarkedForDelete = true + ResourceTypeIPAddressAllocation = common.ResourceTypeIPAddressAllocation +) + +type IPAddressAllocationService struct { + common.Service + ipAddressAllocationStore *IPAddressAllocationStore + VPCService common.VPCServiceProvider +} + +func InitializeIPAddressAllocation(service common.Service, vpcService common.VPCServiceProvider, includeNCP bool) (*IPAddressAllocationService, + error) { + wg := sync.WaitGroup{} + wgDone := make(chan bool) + fatalErrors := make(chan error) + + ipAddressAllocationService := &IPAddressAllocationService{Service: service, VPCService: vpcService} + ipAddressAllocationService.ipAddressAllocationStore = &IPAddressAllocationStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPAddressAllocationCRUID: indexFunc}), + BindingType: model.VpcIpAddressAllocationBindingType(), + }} + + if includeNCP { + wg.Add(2) + go ipAddressAllocationService.InitializeResourceStore(&wg, fatalErrors, ResourceTypeIPAddressAllocation, + []model.Tag{{Scope: String(common.TagScopeNCPCluster), Tag: String(service.NSXClient.NsxConfig.Cluster)}}, + ipAddressAllocationService.ipAddressAllocationStore) + } else { + wg.Add(1) + } + go ipAddressAllocationService.InitializeResourceStore(&wg, fatalErrors, ResourceTypeIPAddressAllocation, + []model.Tag{{Scope: String(common.TagScopeCluster), Tag: String(service.NSXClient.NsxConfig.Cluster)}}, + ipAddressAllocationService.ipAddressAllocationStore) + + go func() { + wg.Wait() + close(wgDone) + }() + select { + case <-wgDone: + break + case err := <-fatalErrors: + close(fatalErrors) + return ipAddressAllocationService, err + } + return ipAddressAllocationService, nil +} + +func (service *IPAddressAllocationService) CreateOrUpdateIPAddressAllocation(obj *v1alpha1.IPAddressAllocation) (bool, error) { + nsxIPAddressAllocation, err := service.BuildIPAddressAllocation(obj) + if err != nil { + return false, err + } + existingIPAddressAllocation, err := service.indexedIPAddressAllocation(obj.UID) + if err != nil { + log.Error(err, "failed to get ipaddressallocation", "UID", obj.UID) + return false, err + } + log.V(1).Info("existing ipaddressallocation", "ipaddressallocation", existingIPAddressAllocation) + ipAddressAllocationUpdated := common.CompareResource(IpAddressAllocationToComparable(existingIPAddressAllocation), + IpAddressAllocationToComparable(nsxIPAddressAllocation)) + + if !ipAddressAllocationUpdated { + log.Info("ipaddressallocation is not changed", "UID", obj.UID) + return false, nil + } + + if err := service.Apply(nsxIPAddressAllocation); err != nil { + return false, err + } + + createdIPAddressAllocation, err := service.indexedIPAddressAllocation(obj.UID) + if err != nil { + log.Error(err, "failed to get created ipaddressallocation", "UID", obj.UID) + return false, err + } + allocation_ips := createdIPAddressAllocation.AllocationIps + if allocation_ips == nil { + return false, fmt.Errorf("ipaddressallocation %s didn't realize available allocation_ips", obj.UID) + } + obj.Status.AllocationIPs = *allocation_ips + return true, nil +} + +func (service *IPAddressAllocationService) Apply(nsxIPAddressAllocation *model.VpcIpAddressAllocation) error { + ns := service.GetIPAddressAllocationNamespace(nsxIPAddressAllocation) + VPCInfo := service.VPCService.ListVPCInfo(ns) + if len(VPCInfo) == 0 { + err := util.NoEffectiveOption{Desc: "no valid org and project for ipaddressallocation"} + return err + } + errPatch := service.NSXClient.IPAddressAllocationClient.Patch(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, VPCInfo[0].ID, *nsxIPAddressAllocation.Id, *nsxIPAddressAllocation) + errPatch = util.NSXApiError(errPatch) + if errPatch != nil { + // not return err, try to get it from nsx, in case if cidr not realized at the first time + // so it can be patched in the next time and reacquire cidr + log.Error(errPatch, "patch failed, try to get it from nsx", "nsxIPAddressAllocation", nsxIPAddressAllocation) + } + // get back from nsx, it contains path which is used to parse vpc info when deleting + nsxIPAddressAllocationNew, errGet := service.NSXClient.IPAddressAllocationClient.Get(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, VPCInfo[0].ID, *nsxIPAddressAllocation.Id) + errGet = util.NSXApiError(errGet) + if errGet != nil { + if errPatch != nil { + return fmt.Errorf("error get %s, error patch %s", errGet.Error(), errPatch.Error()) + } + return errGet + } + if nsxIPAddressAllocationNew.AllocationIps == nil { + err := fmt.Errorf("cidr not realized yet") + return err + } + err := service.ipAddressAllocationStore.Apply(&nsxIPAddressAllocationNew) + if err != nil { + return err + } + log.V(1).Info("successfully created or updated ipaddressallocation", "nsxIPAddressAllocation", nsxIPAddressAllocation) + return nil +} + +func (service *IPAddressAllocationService) DeleteIPAddressAllocation(obj interface{}) error { + var err error + var nsxIPAddressAllocation *model.VpcIpAddressAllocation + switch o := obj.(type) { + case *v1alpha1.IPAddressAllocation: + nsxIPAddressAllocation, err = service.indexedIPAddressAllocation(o.UID) + if err != nil { + log.Error(err, "failed to get ipaddressallocation", "IPAddressAllocation", o) + } + case types.UID: + nsxIPAddressAllocation, err = service.indexedIPAddressAllocation(o) + if err != nil { + log.Error(err, "failed to get ipaddressallocation by UID", "UID", o) + } + case string: + ok := false + obj = service.ipAddressAllocationStore.GetByKey(o) + nsxIPAddressAllocation, ok = obj.(*model.VpcIpAddressAllocation) + if !ok { + log.Error(err, "failed to get ipaddressallocation by key", "key", o) + } + } + if nsxIPAddressAllocation == nil { + log.Error(nil, "failed to get ipaddressallocation from store, skip") + return nil + } + vpcResourceInfo, err := common.ParseVPCResourcePath(*nsxIPAddressAllocation.Path) + if err != nil { + return err + } + err = service.NSXClient.IPAddressAllocationClient.Delete(vpcResourceInfo.OrgID, vpcResourceInfo.ProjectID, vpcResourceInfo.VPCID, *nsxIPAddressAllocation.Id) + if err != nil { + return err + } + nsxIPAddressAllocation.MarkedForDelete = &MarkedForDelete + err = service.ipAddressAllocationStore.Apply(nsxIPAddressAllocation) + if err != nil { + return err + } + log.V(1).Info("successfully deleted nsxIPAddressAllocation", "nsxIPAddressAllocation", nsxIPAddressAllocation) + return nil +} + +func (service *IPAddressAllocationService) ListIPAddressAllocationID() sets.Set[string] { + ipAddressAllocationSet := service.ipAddressAllocationStore.ListIndexFuncValues(common.TagScopeIPAddressAllocationCRUID) + return ipAddressAllocationSet +} + +func (service *IPAddressAllocationService) ListIPAddressAllocationKeys() []string { + ipAddressAllocationKeys := service.ipAddressAllocationStore.ListKeys() + return ipAddressAllocationKeys +} + +func (service *IPAddressAllocationService) GetIPAddressAllocationNamespace(nsxIPAddressAllocation *model.VpcIpAddressAllocation) string { + for _, tag := range nsxIPAddressAllocation.Tags { + if *tag.Scope == common.TagScopeNamespace { + return *tag.Tag + } + } + return "" +} + +func (service *IPAddressAllocationService) Cleanup(ctx context.Context) error { + keys := service.ListIPAddressAllocationKeys() + log.Info("cleaning up ipaddressallocation", "count", len(keys)) + for _, key := range keys { + select { + case <-ctx.Done(): + return util.TimeoutFailed + default: + err := service.DeleteIPAddressAllocation(key) + if err != nil { + return err + } + } + } + return nil +} diff --git a/pkg/nsx/services/ipaddressallocation/store.go b/pkg/nsx/services/ipaddressallocation/store.go new file mode 100644 index 000000000..e0efdcdac --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/store.go @@ -0,0 +1,90 @@ +package ipaddressallocation + +import ( + "errors" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/apimachinery/pkg/types" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func keyFunc(obj interface{}) (string, error) { + switch v := obj.(type) { + case *model.VpcIpAddressAllocation: + return *v.Id, nil + case *model.GenericPolicyRealizedResource: + return *v.Id, nil + default: + return "", errors.New("keyFunc doesn't support unknown type") + } +} + +func indexFunc(obj interface{}) ([]string, error) { + res := make([]string, 0, 5) + switch v := obj.(type) { + case *model.VpcIpAddressAllocation: + return filterTag(v.Tags), nil + case *model.GenericPolicyRealizedResource: + return filterTag(v.Tags), nil + default: + return res, errors.New("indexFunc doesn't support unknown type") + } +} + +var filterTag = func(v []model.Tag) []string { + res := make([]string, 0, 5) + for _, tag := range v { + if *tag.Scope == common.TagScopeIPAddressAllocationCRUID { + res = append(res, *tag.Tag) + } + } + return res +} + +type IPAddressAllocationStore struct { + common.ResourceStore +} + +func (ipAddressAllocationStore *IPAddressAllocationStore) Apply(i interface{}) error { + ipAddressAllocation := i.(*model.VpcIpAddressAllocation) + if ipAddressAllocation.MarkedForDelete != nil && *ipAddressAllocation.MarkedForDelete { + err := ipAddressAllocationStore.Delete(ipAddressAllocation) + if err != nil { + return err + } + log.V(1).Info("delete ipAddressAllocation from store", "ipAddressAllocation", ipAddressAllocation) + } else { + err := ipAddressAllocationStore.Add(ipAddressAllocation) + if err != nil { + return err + } + log.V(1).Info("add ipAddressAllocation to store", "ipAddressAllocation", ipAddressAllocation) + } + return nil +} + +func (service *IPAddressAllocationService) indexedIPAddressAllocation(uid types.UID) (*model.VpcIpAddressAllocation, error) { + nsxIPAddressAllocation, err := service.ipAddressAllocationStore.GetByIndex(uid) + if err != nil { + return nil, err + } + return nsxIPAddressAllocation, nil +} + +func (ipAddressAllocationStore *IPAddressAllocationStore) GetByIndex(uid types.UID) (*model.VpcIpAddressAllocation, error) { + nsxIPAddressAllocation := &model.VpcIpAddressAllocation{} + indexResults, err := ipAddressAllocationStore.ResourceStore.ByIndex(common.TagScopeIPAddressAllocationCRUID, string(uid)) + if err != nil { + log.Error(err, "failed to get ipaddressallocation", "UID", string(uid)) + return nil, err + } + if len(indexResults) > 0 { + t := indexResults[0].(*model.VpcIpAddressAllocation) + nsxIPAddressAllocation = t + } else { + log.Info("did not get ipaddressallocation with index", "UID", string(uid)) + return nil, nil + } + return nsxIPAddressAllocation, nil +} diff --git a/pkg/nsx/services/ipaddressallocation/store_test.go b/pkg/nsx/services/ipaddressallocation/store_test.go new file mode 100644 index 000000000..002f6a429 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/store_test.go @@ -0,0 +1,98 @@ +package ipaddressallocation + +import ( + "fmt" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func TestIPAddressAllocationStore_CRUDResource(t *testing.T) { + ipAddressAllocationCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPAddressAllocationCRUID: indexFunc}) + resourceStore := common.ResourceStore{ + Indexer: ipAddressAllocationCacheIndexer, + BindingType: model.VpcIpAddressAllocationBindingType(), + } + ipAddressAllocationStore := &IPAddressAllocationStore{ResourceStore: resourceStore} + type args struct { + i interface{} + } + tests := []struct { + name string + args args + wantErr assert.ErrorAssertionFunc + }{ + {"1", args{i: &model.VpcIpAddressAllocation{Id: String("1")}}, assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.wantErr(t, ipAddressAllocationStore.Apply(tt.args.i), fmt.Sprintf("Apply(%v)", tt.args.i)) + }) + } +} + +func TestIPAddressAllocationStore_GetByIndex(t *testing.T) { + p := &model.VpcIpAddressAllocation{Id: String("1"), DisplayName: String("1"), + Tags: []model.Tag{{Scope: String(common.TagScopeIPAddressAllocationCRUID), + Tag: String("1")}}} + ipAddressAllocationStore := &IPAddressAllocationStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPAddressAllocationCRUID: indexFunc}), + BindingType: model.VpcIpAddressBindingType(), + }} + _ = ipAddressAllocationStore.Apply(p) + type args struct { + uid types.UID + } + tests := []struct { + name string + args args + want *model.VpcIpAddressAllocation + wantErr bool + }{ + {"1", args{uid: "1"}, &model.VpcIpAddressAllocation{Id: String("1"), DisplayName: String("1"), + Tags: []model.Tag{{Scope: String(common.TagScopeIPAddressAllocationCRUID), Tag: String("1")}}}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ipAddressAllocationStore.GetByIndex(tt.args.uid) + if (err != nil) != tt.wantErr { + t.Errorf("indexedIPAddressAllocation() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("indexedIPAddressAllocation() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_indexFunc(t *testing.T) { + mId, mTag, mScope := "11111", "11111", common.TagScopeIPAddressAllocationCRUID + m := &model.VpcIpAddressAllocation{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + } + t.Run("1", func(t *testing.T) { + got, _ := indexFunc(m) + if !reflect.DeepEqual(got, []string{"11111"}) { + t.Errorf("indexFunc() = %v, want %v", got, model.Tag{Tag: &mTag, Scope: &mScope}) + } + }) +} + +func Test_keyFunc(t *testing.T) { + Id := "11111" + g := &model.VpcIpAddressAllocation{Id: &Id} + t.Run("2", func(t *testing.T) { + got, _ := keyFunc(g) + if got != "11111" { + t.Errorf("keyFunc() = %v, want %v", got, "11111") + } + }) +} diff --git a/pkg/nsx/services/ippool/builder.go b/pkg/nsx/services/ippool/builder.go deleted file mode 100644 index b42a643d0..000000000 --- a/pkg/nsx/services/ippool/builder.go +++ /dev/null @@ -1,118 +0,0 @@ -package ippool - -import ( - "fmt" - "strings" - - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/util" -) - -var ( - Int64 = common.Int64 - String = common.String -) - -const ( - IPPOOLPREFIX = "ipc" - IPPOOLSUBNETPREFIX = "ibs" -) - -func (service *IPPoolService) BuildIPPool(IPPool *v1alpha2.IPPool) (*model.IpAddressPool, []*model.IpAddressPoolBlockSubnet) { - return &model.IpAddressPool{ - Id: String(service.buildIPPoolID(IPPool)), - DisplayName: String(service.buildIPPoolName(IPPool)), - Tags: service.buildIPPoolTags(IPPool), - }, service.buildIPSubnets(IPPool) -} - -func (service *IPPoolService) buildIPPoolID(IPPool *v1alpha2.IPPool) string { - return util.GenerateID(string(IPPool.UID), IPPOOLPREFIX, "", "") -} - -func (service *IPPoolService) buildIPPoolName(IPPool *v1alpha2.IPPool) string { - return util.GenerateDisplayName(IPPool.ObjectMeta.Name, IPPOOLPREFIX, "", "", getCluster(service)) -} - -func (service *IPPoolService) buildIPPoolTags(IPPool *v1alpha2.IPPool) []model.Tag { - basicTags := util.BuildBasicTags(getCluster(service), IPPool, "") - tags := util.AppendTags(basicTags, []model.Tag{ - {Scope: String(common.TagScopeIPPoolCRType), Tag: String(IPPool.Spec.Type)}}, - ) - return tags -} - -func (service *IPPoolService) buildIPSubnets(IPPool *v1alpha2.IPPool) []*model.IpAddressPoolBlockSubnet { - var IPSubnets []*model.IpAddressPoolBlockSubnet - for _, subnetRequest := range IPPool.Spec.Subnets { - IPSubnet := service.buildIPSubnet(IPPool, subnetRequest) - if IPSubnet != nil { - IPSubnets = append(IPSubnets, IPSubnet) - } - } - return IPSubnets -} - -func (service *IPPoolService) buildIPSubnetID(IPPool *v1alpha2.IPPool, subnetRequest *v1alpha2.SubnetRequest) string { - return util.GenerateID(string(IPPool.UID), IPPOOLSUBNETPREFIX, subnetRequest.Name, "") -} - -func (service *IPPoolService) buildIPSubnetName(IPPool *v1alpha2.IPPool, subnetRequest *v1alpha2.SubnetRequest) string { - return util.GenerateDisplayName(IPPool.ObjectMeta.Name, IPPOOLSUBNETPREFIX, subnetRequest.Name, "", getCluster(service)) -} - -func (service *IPPoolService) buildIPSubnetTags(IPPool *v1alpha2.IPPool, subnetRequest *v1alpha2.SubnetRequest) []model.Tag { - basicTags := util.BuildBasicTags(getCluster(service), IPPool, "") - tags := util.AppendTags(basicTags, []model.Tag{ - {Scope: String(common.TagScopeIPSubnetName), Tag: String(subnetRequest.Name)}}, - ) - return tags -} - -func (service *IPPoolService) buildIPSubnetIntentPath(IPPool *v1alpha2.IPPool, subnetRequest *v1alpha2.SubnetRequest) string { - if IPPool.Spec.Type == common.IPPoolTypePrivate { - VPCInfo := service.VPCService.ListVPCInfo(IPPool.Namespace) - if len(VPCInfo) == 0 { - return "" - } - return strings.Join([]string{fmt.Sprintf("/orgs/%s/projects/%s/infra/ip-pools", VPCInfo[0].OrgID, VPCInfo[0].ProjectID), - service.buildIPPoolID(IPPool), - "ip-subnets", service.buildIPSubnetID(IPPool, subnetRequest)}, "/") - } else { - return strings.Join([]string{"/infra/ip-pools", service.buildIPPoolID(IPPool), - "ip-subnets", service.buildIPSubnetID(IPPool, subnetRequest)}, "/") - } -} - -func (service *IPPoolService) buildIPSubnet(IPPool *v1alpha2.IPPool, subnetRequest v1alpha2.SubnetRequest) *model.IpAddressPoolBlockSubnet { - IpBlockPath := String("") - VPCInfo := service.VPCService.ListVPCInfo(IPPool.Namespace) - if len(VPCInfo) == 0 { - log.Error(nil, "failed to find VPCInfo for IPPool CR", "IPPool", IPPool.Name, "namespace", IPPool.Namespace) - return nil - } - var IpBlockPathList []string - if IPPool.Spec.Type == common.IPPoolTypePrivate { - IpBlockPathList = VPCInfo[0].PrivateIpv4Blocks - } else { - IpBlockPathList = VPCInfo[0].ExternalIPv4Blocks - } - for _, ipBlockPath := range IpBlockPathList { - if util.Contains(service.ExhaustedIPBlock, ipBlockPath) { - continue - } - IpBlockPath = String(ipBlockPath) - log.V(2).Info("use ip block path", "ip block path", ipBlockPath) - } - - return &model.IpAddressPoolBlockSubnet{ - Id: String(service.buildIPSubnetID(IPPool, &subnetRequest)), - DisplayName: String(service.buildIPSubnetName(IPPool, &subnetRequest)), - Tags: service.buildIPSubnetTags(IPPool, &subnetRequest), - Size: Int64(util.CalculateSubnetSize(subnetRequest.PrefixLength)), - IpBlockPath: IpBlockPath, - } -} diff --git a/pkg/nsx/services/ippool/builder_test.go b/pkg/nsx/services/ippool/builder_test.go deleted file mode 100644 index 8b7930378..000000000 --- a/pkg/nsx/services/ippool/builder_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package ippool - -import ( - "reflect" - "strings" - "testing" - - "github.com/agiledragon/gomonkey/v2" - "github.com/stretchr/testify/assert" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" -) - -func TestIPPoolService_BuildIPPool(t *testing.T) { - ipPoolService := fakeService() - - ipPool := &v1alpha2.IPPool{ - ObjectMeta: v1.ObjectMeta{ - Name: "ippool1", - UID: "uuid1", - }, - Spec: v1alpha2.IPPoolSpec{ - Type: "public", - Subnets: []v1alpha2.SubnetRequest{ - { - Name: "subnet1", - PrefixLength: 24, - }, - }, - }, - } - - want := &model.IpAddressPool{ - DisplayName: String("ipc-k8scl-one:test-ippool1"), - Id: String("ipc_uuid1"), - Tags: []model.Tag{ - {Scope: String("nsx-op/cluster"), Tag: String("k8scl-one:test")}, - {Scope: String("nsx-op/version"), Tag: String(strings.Join(common.TagValueVersion, "."))}, - {Scope: String("nsx-op/namespace"), Tag: String("")}, - {Scope: String("nsx-op/ippool_name"), Tag: String("ippool1")}, - { - Scope: String("nsx-op/ippool_uid"), - Tag: String("uuid1"), - }, - {Scope: String("nsx-op/ippool_type"), Tag: String("public")}, - }, - } - - want2 := model.IpAddressPoolBlockSubnet{ - DisplayName: String("ibs-k8scl-one:test-ippool1-subnet1"), - Id: String("ibs_uuid1_subnet1"), - IpBlockPath: String("/infra/ip-blocks/block-test"), - Tags: []model.Tag{ - {Scope: String("nsx-op/cluster"), Tag: String("k8scl-one:test")}, - {Scope: String("nsx-op/version"), Tag: String(strings.Join(common.TagValueVersion, "."))}, - {Scope: String("nsx-op/namespace"), Tag: String("")}, - {Scope: String("nsx-op/ippool_name"), Tag: String("ippool1")}, - {Scope: String("nsx-op/ippool_uid"), Tag: String("uuid1")}, - {Scope: String("nsx-op/ipsubnet_name"), Tag: String("subnet1")}, - }, - Size: Int64(256), - } - - vpcinfolist := []common.VPCResourceInfo{ - {ExternalIPv4Blocks: []string{"/infra/ip-blocks/block-test"}}, - } - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: vpcCacheIndexer, - BindingType: model.VpcBindingType(), - } - vpcStore := &vpc.VPCStore{ResourceStore: resourceStore} - ipPoolService.VPCService = &vpc.VPCService{VpcStore: vpcStore} - patch := gomonkey.ApplyMethod(reflect.TypeOf(ipPoolService.VPCService), "ListVPCInfo", func(vpcService *vpc.VPCService, - ns string, - ) []common.VPCResourceInfo { - return vpcinfolist - }) - defer patch.Reset() - - type args struct { - IPPool *v1alpha2.IPPool - } - tests := []struct { - name string - args args - want *model.IpAddressPool - want1 []*model.IpAddressPoolBlockSubnet - }{ - {"test1", args{ipPool}, want, []*model.IpAddressPoolBlockSubnet{&want2}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, got1 := ipPoolService.BuildIPPool(tt.args.IPPool) - assert.Equalf(t, tt.want, got, "BuildIPPool(%v)", tt.args.IPPool) - assert.Equalf(t, tt.want1, got1, "BuildIPPool(%v)", tt.args.IPPool) - }) - } -} diff --git a/pkg/nsx/services/ippool/compare.go b/pkg/nsx/services/ippool/compare.go deleted file mode 100644 index 2b9a65bf2..000000000 --- a/pkg/nsx/services/ippool/compare.go +++ /dev/null @@ -1,63 +0,0 @@ -package ippool - -import ( - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -type ( - IpAddressPool model.IpAddressPool - IpAddressPoolBlockSubnet model.IpAddressPoolBlockSubnet -) - -type Comparable = common.Comparable - -func (iap *IpAddressPool) Key() string { - return *iap.Id -} - -func (iapbs *IpAddressPoolBlockSubnet) Key() string { - return *iapbs.Id -} - -func (iap *IpAddressPool) Value() data.DataValue { - s := &IpAddressPool{Id: iap.Id, DisplayName: iap.DisplayName, Tags: iap.Tags} - dataValue, _ := ComparableToIpAddressPool(s).GetDataValue__() - return dataValue -} - -func (iapbs *IpAddressPoolBlockSubnet) Value() data.DataValue { - r := &IpAddressPoolBlockSubnet{Id: iapbs.Id, DisplayName: iapbs.Id, Tags: iapbs.Tags} - dataValue, _ := ComparableToIpAddressPoolBlockSubnet(r).GetDataValue__() - return dataValue -} - -func IpAddressPoolToComparable(iap *model.IpAddressPool) Comparable { - return (*IpAddressPool)(iap) -} - -func IpAddressPoolBlockSubnetsToComparable(iapbs []*model.IpAddressPoolBlockSubnet) []Comparable { - res := make([]Comparable, 0, len(iapbs)) - for i := range iapbs { - res = append(res, (*IpAddressPoolBlockSubnet)(iapbs[i])) - } - return res -} - -func ComparableToIpAddressPool(iap Comparable) *model.IpAddressPool { - return (*model.IpAddressPool)(iap.(*IpAddressPool)) -} - -func ComparableToIpAddressPoolBlockSubnets(iapbs []Comparable) []*model.IpAddressPoolBlockSubnet { - res := make([]*model.IpAddressPoolBlockSubnet, 0, len(iapbs)) - for _, iapb := range iapbs { - res = append(res, (*model.IpAddressPoolBlockSubnet)(iapb.(*IpAddressPoolBlockSubnet))) - } - return res -} - -func ComparableToIpAddressPoolBlockSubnet(iapbs Comparable) *model.IpAddressPoolBlockSubnet { - return (*model.IpAddressPoolBlockSubnet)(iapbs.(*IpAddressPoolBlockSubnet)) -} diff --git a/pkg/nsx/services/ippool/compare_test.go b/pkg/nsx/services/ippool/compare_test.go deleted file mode 100644 index 022ea115c..000000000 --- a/pkg/nsx/services/ippool/compare_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package ippool - -import ( - "reflect" - "testing" - - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" -) - -func TestComparableToIpAddressPool(t *testing.T) { - type args struct { - iap Comparable - } - tests := []struct { - name string - args args - want *model.IpAddressPool - }{ - {"1", args{&IpAddressPool{Id: String("1")}}, &model.IpAddressPool{Id: String("1")}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ComparableToIpAddressPool(tt.args.iap); !reflect.DeepEqual(got, tt.want) { - t.Errorf("ComparableToIpAddressPool() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestComparableToIpAddressPoolBlockSubnet(t *testing.T) { - type args struct { - iapbs Comparable - } - tests := []struct { - name string - args args - want *model.IpAddressPoolBlockSubnet - }{ - {"1", args{&IpAddressPoolBlockSubnet{Id: String("1")}}, &model.IpAddressPoolBlockSubnet{Id: String("1")}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ComparableToIpAddressPoolBlockSubnet(tt.args.iapbs); !reflect.DeepEqual(got, tt.want) { - t.Errorf("ComparableToIpAddressPoolBlockSubnet() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestComparableToIpAddressPoolBlockSubnets(t *testing.T) { - type args struct { - iapbs []Comparable - } - tests := []struct { - name string - args args - want []*model.IpAddressPoolBlockSubnet - }{ - {"1", args{[]Comparable{&IpAddressPoolBlockSubnet{Id: String("1")}}}, []*model.IpAddressPoolBlockSubnet{{Id: String("1")}}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ComparableToIpAddressPoolBlockSubnets(tt.args.iapbs); !reflect.DeepEqual(got, tt.want) { - t.Errorf("ComparableToIpAddressPoolBlockSubnets() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIpAddressPoolBlockSubnet_Key(t *testing.T) { - tests := []struct { - name string - iapbs IpAddressPoolBlockSubnet - want string - }{ - {"1", IpAddressPoolBlockSubnet{Id: String("1")}, "1"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.iapbs.Key(); got != tt.want { - t.Errorf("Key() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIpAddressPoolBlockSubnet_Value(t *testing.T) { - m := model.IpAddressPoolBlockSubnet{Id: String("1"), DisplayName: String("1"), Tags: []model.Tag{{Scope: String("1"), Tag: String("1")}}} - v, _ := m.GetDataValue__() - p := IpAddressPoolBlockSubnet{Id: String("1"), DisplayName: String("1"), Tags: []model.Tag{{Scope: String("1"), Tag: String("1")}}} - tests := []struct { - name string - iapbs IpAddressPoolBlockSubnet - want data.DataValue - }{ - {"1", p, v}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.iapbs.Value(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Value() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIpAddressPoolBlockSubnetsToComparable(t *testing.T) { - type args struct { - iapbs []*model.IpAddressPoolBlockSubnet - } - tests := []struct { - name string - args args - want []Comparable - }{ - {"1", args{[]*model.IpAddressPoolBlockSubnet{{Id: String("1")}}}, []Comparable{&IpAddressPoolBlockSubnet{Id: String("1")}}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := IpAddressPoolBlockSubnetsToComparable(tt.args.iapbs); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IpAddressPoolBlockSubnetsToComparable() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIpAddressPoolToComparable(t *testing.T) { - type args struct { - iap *model.IpAddressPool - } - tests := []struct { - name string - args args - want Comparable - }{ - {"1", args{&model.IpAddressPool{Id: String("1")}}, &IpAddressPool{Id: String("1")}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := IpAddressPoolToComparable(tt.args.iap); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IpAddressPoolToComparable() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIpAddressPool_Key(t *testing.T) { - tests := []struct { - name string - iap IpAddressPool - want string - }{ - {"1", IpAddressPool{Id: String("1")}, "1"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.iap.Key(); got != tt.want { - t.Errorf("Key() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIpAddressPool_Value(t *testing.T) { - m := model.IpAddressPool{Id: String("1"), DisplayName: String("1"), Tags: []model.Tag{{Scope: String("1"), Tag: String("1")}}} - v, _ := m.GetDataValue__() - p := IpAddressPool{Id: String("1"), DisplayName: String("1"), Tags: []model.Tag{{Scope: String("1"), Tag: String("1")}}} - tests := []struct { - name string - iap IpAddressPool - want data.DataValue - }{ - {"1", p, v}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.iap.Value(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Value() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/nsx/services/ippool/fake_test.go b/pkg/nsx/services/ippool/fake_test.go deleted file mode 100644 index f58ce6706..000000000 --- a/pkg/nsx/services/ippool/fake_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package ippool - -import ( - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "k8s.io/client-go/tools/cache" - - "github.com/vmware-tanzu/nsx-operator/pkg/config" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -type fakeQueryClient struct { -} - -func (qIface *fakeQueryClient) List(queryParam string, cursorParam *string, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.SearchResponse, error) { - cursor := "2" - resultCount := int64(2) - return model.SearchResponse{ - Results: []*data.StructValue{data.NewStructValue("test1", nil), data.NewStructValue("test2", nil)}, - Cursor: &cursor, ResultCount: &resultCount, - }, nil -} - -type fakeProjectInfraClient struct { -} - -func (f fakeProjectInfraClient) Get(orgIdParam string, projectIdParam string, basePathParam *string, filterParam *string, typeFilterParam *string) (model.Infra, error) { - return model.Infra{}, nil -} - -func (f fakeProjectInfraClient) Patch(orgIdParam string, projectIdParam string, infraParam model.Infra, enforceRevisionCheckParam *bool) error { - return nil -} - -type fakeRealizedEntitiesClient struct { -} - -func (f fakeRealizedEntitiesClient) List(_ string, _ string, _ string, _ *string) (model.GenericPolicyRealizedResourceListResult, error) { - a := model.GenericPolicyRealizedResourceListResult{ - Results: []model.GenericPolicyRealizedResource{ - { - EntityType: String("IpBlockSubnet"), - ExtendedAttributes: []model.AttributeVal{ - {Key: String("cidr"), Values: []string{"1.1.1.1/24"}}, - }, - }, - }, - } - return a, nil -} - -func fakeService() *IPPoolService { - c := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) - cluster, _ := nsx.NewCluster(c) - rc, _ := cluster.NewRestConnector() - ipPoolStore := &IPPoolStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBindingType(), - }} - ipPoolBlockSubnetStore := &IPPoolBlockSubnetStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBlockSubnetBindingType(), - }} - - service := &IPPoolService{ - Service: common.Service{ - NSXClient: &nsx.Client{ - QueryClient: &fakeQueryClient{}, - RestConnector: rc, - RealizedEntitiesClient: &fakeRealizedEntitiesClient{}, - ProjectInfraClient: &fakeProjectInfraClient{}, - NsxConfig: &config.NSXOperatorConfig{ - CoeConfig: &config.CoeConfig{ - Cluster: "k8scl-one:test", - }, - }, - }, - NSXConfig: &config.NSXOperatorConfig{ - CoeConfig: &config.CoeConfig{ - Cluster: "k8scl-one:test", - }, - }, - }, - ipPoolStore: ipPoolStore, - ipPoolBlockSubnetStore: ipPoolBlockSubnetStore, - } - return service -} diff --git a/pkg/nsx/services/ippool/ippool.go b/pkg/nsx/services/ippool/ippool.go deleted file mode 100644 index 3028d6975..000000000 --- a/pkg/nsx/services/ippool/ippool.go +++ /dev/null @@ -1,292 +0,0 @@ -package ippool - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/cache" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" - "github.com/vmware-tanzu/nsx-operator/pkg/logger" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" -) - -var ( - log = logger.Log - MarkedForDelete = true - EnforceRevisionCheckParam = false - ResourceTypeIPPool = common.ResourceTypeIPPool - ResourceTypeIPPoolBlockSubnet = common.ResourceTypeIPPoolBlockSubnet - NewConverter = common.NewConverter -) - -type IPPoolService struct { - common.Service - ipPoolStore *IPPoolStore - ipPoolBlockSubnetStore *IPPoolBlockSubnetStore - ExhaustedIPBlock []string - VPCService common.VPCServiceProvider -} - -func InitializeIPPool(service common.Service, vpcService common.VPCServiceProvider) (*IPPoolService, error) { - wg := sync.WaitGroup{} - wgDone := make(chan bool) - fatalErrors := make(chan error) - - wg.Add(2) - - ipPoolService := &IPPoolService{Service: service, VPCService: vpcService} - ipPoolService.ipPoolStore = &IPPoolStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBindingType(), - }} - ipPoolService.ipPoolBlockSubnetStore = &IPPoolBlockSubnetStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBlockSubnetBindingType(), - }} - - tags := []model.Tag{ - {Scope: String(common.TagScopeIPPoolCRUID)}, - } - go ipPoolService.InitializeResourceStore(&wg, fatalErrors, ResourceTypeIPPool, tags, ipPoolService.ipPoolStore) - go ipPoolService.InitializeResourceStore(&wg, fatalErrors, ResourceTypeIPPoolBlockSubnet, tags, ipPoolService.ipPoolBlockSubnetStore) - - go func() { - wg.Wait() - close(wgDone) - }() - select { - case <-wgDone: - break - case err := <-fatalErrors: - close(fatalErrors) - return ipPoolService, err - } - return ipPoolService, nil -} - -func (service *IPPoolService) CreateOrUpdateIPPool(obj *v1alpha2.IPPool) (bool, bool, error) { - nsxIPPool, nsxIPSubnets := service.BuildIPPool(obj) - if len(obj.Spec.Subnets) != 0 && len(nsxIPSubnets) == 0 { - err := util.NoEffectiveOption{Desc: "no valid ip block for ippool"} - return false, false, err - } - for _, ipSubnet := range nsxIPSubnets { - if ipSubnet.IpBlockPath == nil || *ipSubnet.IpBlockPath == "" { - return false, false, util.IPBlockAllExhaustedError{Desc: "all ip blocks are exhausted"} - } - } - existingIPPool, existingIPSubnets, err := service.indexedIPPoolAndIPPoolSubnets(obj.UID) - if err != nil { - log.Error(err, "failed to get ip pool and ip pool subnets by UID", "UID", obj.UID) - return false, false, err - } - log.V(1).Info("existing ippool and ip subnets", "existingIPPool", existingIPPool, "existingIPSubnets", existingIPSubnets) - ipPoolSubnetsUpdated := false - ipPoolUpdated := common.CompareResource(IpAddressPoolToComparable(existingIPPool), IpAddressPoolToComparable(nsxIPPool)) - changed, stale := common.CompareResources(IpAddressPoolBlockSubnetsToComparable(existingIPSubnets), IpAddressPoolBlockSubnetsToComparable(nsxIPSubnets)) - changedIPSubnets, staleIPSubnets := ComparableToIpAddressPoolBlockSubnets(changed), ComparableToIpAddressPoolBlockSubnets(stale) - for i := len(staleIPSubnets) - 1; i >= 0; i-- { - staleIPSubnets[i].MarkedForDelete = &MarkedForDelete - } - finalIPSubnets := append(changedIPSubnets, staleIPSubnets...) - if len(finalIPSubnets) > 0 { - ipPoolSubnetsUpdated = true - } - - if err := service.Apply(nsxIPPool, finalIPSubnets, ipPoolUpdated, ipPoolSubnetsUpdated); err != nil { - return false, false, err - } - - realizedSubnets, subnetCidrUpdated, e := service.AcquireRealizedSubnetIP(obj) - if e != nil { - return false, false, e - } - obj.Status.Subnets = realizedSubnets - return subnetCidrUpdated, ipPoolSubnetsUpdated, nil -} - -func (service *IPPoolService) Apply(nsxIPPool *model.IpAddressPool, nsxIPSubnets []*model.IpAddressPoolBlockSubnet, IPPoolUpdated bool, IPPoolSubnetsUpdated bool) error { - if !(IPPoolUpdated || IPPoolSubnetsUpdated) { - return nil - } - infraIPPool, err := service.WrapHierarchyIPPool(nsxIPPool, nsxIPSubnets) - if err != nil { - return err - } - // Get IPPool Type from nsxIPPool - IPPoolType := common.IPPoolTypePrivate - for _, tag := range nsxIPPool.Tags { - if *tag.Scope == common.TagScopeIPPoolCRType { - IPPoolType = *tag.Tag - break - } - } - - if IPPoolType == common.IPPoolTypePrivate { - ns := service.GetIPPoolNamespace(nsxIPPool) - VPCInfo := service.VPCService.ListVPCInfo(ns) - if len(VPCInfo) == 0 { - err = util.NoEffectiveOption{Desc: "no valid org and project for ippool"} - } else { - err = service.NSXClient.ProjectInfraClient.Patch(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, *infraIPPool, - &EnforceRevisionCheckParam) - } - } else if IPPoolType == common.IPPoolTypePublic { - err = service.NSXClient.InfraClient.Patch(*infraIPPool, &EnforceRevisionCheckParam) - } else { - err = util.NoEffectiveOption{Desc: "not valid IPPool type"} - } - if err != nil { - return err - } - if IPPoolUpdated { - err = service.ipPoolStore.Apply(nsxIPPool) - if err != nil { - return err - } - } - if IPPoolSubnetsUpdated { - err = service.ipPoolBlockSubnetStore.Apply(nsxIPSubnets) - if err != nil { - return err - } - } - log.V(1).Info("successfully created or updated ippool and ip subnets", "nsxIPPool", nsxIPPool) - return nil -} - -func (service *IPPoolService) AcquireRealizedSubnetIP(obj *v1alpha2.IPPool) ([]v1alpha2.SubnetResult, bool, error) { - realizedSubnets := []v1alpha2.SubnetResult{} - subnetCidrUpdated := false - for _, subnet := range obj.Spec.Subnets { - subnetRequest := subnet - // check if the subnet is already realized - realized := false - realizedSubnet := v1alpha2.SubnetResult{Name: subnetRequest.Name} - for _, statusSubnet := range obj.Status.Subnets { - if statusSubnet.Name == subnetRequest.Name && statusSubnet.CIDR != "" { - realizedSubnet.CIDR = statusSubnet.CIDR - realized = true - break - } - } - if !realized { - cidr, err := service.acquireCidr(obj, &subnetRequest, common.RealizeMaxRetries) - if err != nil { - return nil, subnetCidrUpdated, err - } - if cidr != "" { - subnetCidrUpdated = true - } - realizedSubnet.CIDR = cidr - } - realizedSubnets = append(realizedSubnets, realizedSubnet) - } - return realizedSubnets, subnetCidrUpdated, nil -} - -func (service *IPPoolService) DeleteIPPool(obj interface{}) error { - var err error - var nsxIPPool *model.IpAddressPool - nsxIPSubnets := make([]*model.IpAddressPoolBlockSubnet, 0) - switch o := obj.(type) { - case *v1alpha2.IPPool: - nsxIPPool, nsxIPSubnets = service.BuildIPPool(o) - if err != nil { - log.Error(err, "failed to build ip pool", "IPPool", o) - return err - } - case types.UID: - nsxIPPool, nsxIPSubnets, err = service.indexedIPPoolAndIPPoolSubnets(o) - if err != nil { - log.Error(err, "failed to get ip pool and ip pool subnets by UID", "UID", o) - return err - } - } - nsxIPPool.MarkedForDelete = &MarkedForDelete - for i := len(nsxIPSubnets) - 1; i >= 0; i-- { - nsxIPSubnets[i].MarkedForDelete = &MarkedForDelete - } - if err := service.Apply(nsxIPPool, nsxIPSubnets, true, true); err != nil { - return err - } - log.V(1).Info("successfully deleted nsxIPPool", "nsxIPPool", nsxIPPool) - return nil -} - -func (service *IPPoolService) acquireCidr(obj *v1alpha2.IPPool, subnetRequest *v1alpha2.SubnetRequest, retry int) (string, error) { - intentPath := service.buildIPSubnetIntentPath(obj, subnetRequest) - if intentPath == "" { - return "", fmt.Errorf("failed to build intent path for ip pool %s, subnetRequest %s", obj.Name, subnetRequest.Name) - } - VPCInfo := service.VPCService.ListVPCInfo(obj.Namespace) - var err error - if len(VPCInfo) == 0 { - err = util.NoEffectiveOption{Desc: "no effective org and project for ippool"} - return "", err - } - m, err := service.NSXClient.RealizedEntitiesClient.List(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, intentPath, nil) - if err != nil { - return "", err - } - for _, realizedEntity := range m.Results { - if *realizedEntity.EntityType == "IpBlockSubnet" { - for _, attr := range realizedEntity.ExtendedAttributes { - if *attr.Key == "cidr" { - cidr := attr.Values[0] - log.V(1).Info("successfully realized ippool subnet from ipblock", "subnetRequest.Name", subnetRequest.Name, "cidr", cidr) - return cidr, nil - } - } - } - } - if retry > 0 { - log.V(1).Info("failed to acquire subnet cidr, retrying...", "subnet request", subnetRequest, "retry", retry) - time.Sleep(30 * time.Second) - cidr, e := service.acquireCidr(obj, subnetRequest, retry-1) - return cidr, e - } else { - log.V(1).Info("failed to acquire subnet cidr after multiple retries", "subnet request", subnetRequest) - return "", nil - } -} - -func (service *IPPoolService) ListIPPoolID() sets.Set[string] { - ipPoolSet := service.ipPoolStore.ListIndexFuncValues(common.TagScopeIPPoolCRUID) - ipPoolSubnetSet := service.ipPoolBlockSubnetStore.ListIndexFuncValues(common.TagScopeIPPoolCRUID) - return ipPoolSet.Union(ipPoolSubnetSet) -} - -// GetIPPoolNamespace Get IPPool's namespace by tags -func (service *IPPoolService) GetIPPoolNamespace(nsxIPPool *model.IpAddressPool) string { - for _, tag := range nsxIPPool.Tags { - if *tag.Scope == common.TagScopeNamespace { - return *tag.Tag - } - } - return "" -} - -func (service *IPPoolService) Cleanup(ctx context.Context) error { - uids := service.ListIPPoolID() - log.Info("cleaning up ippool", "count", len(uids)) - for uid := range uids { - select { - case <-ctx.Done(): - return util.TimeoutFailed - default: - err := service.DeleteIPPool(types.UID(uid)) - if err != nil { - return err - } - } - } - return nil -} diff --git a/pkg/nsx/services/ippool/ippool_test.go b/pkg/nsx/services/ippool/ippool_test.go deleted file mode 100644 index a9d02c849..000000000 --- a/pkg/nsx/services/ippool/ippool_test.go +++ /dev/null @@ -1,289 +0,0 @@ -package ippool - -import ( - "fmt" - "reflect" - "sync" - "testing" - - "github.com/agiledragon/gomonkey/v2" - "github.com/stretchr/testify/assert" - "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/cache" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" -) - -func TestIPPoolService_ListIPPoolID(t *testing.T) { - ipPoolService := fakeService() - p := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - _ = ipPoolService.ipPoolStore.Apply(p) - - tests := []struct { - name string - want sets.Set[string] - }{ - {"test", sets.New[string]("1")}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, ipPoolService.ListIPPoolID(), "ListIPPoolID()") - }) - } -} - -func TestIPPoolService_acquireCidr(t *testing.T) { - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: vpcCacheIndexer, - BindingType: model.VpcBindingType(), - } - ipPoolService := fakeService() - vpcStore := &vpc.VPCStore{ResourceStore: resourceStore} - ipPoolService.VPCService = &vpc.VPCService{VpcStore: vpcStore} - patches := gomonkey.ApplyMethod(reflect.TypeOf(ipPoolService.VPCService), "ListVPCInfo", func(_ *vpc.VPCService, ns string) []common.VPCResourceInfo { - id := "vpc-1" - return []common.VPCResourceInfo{{OrgID: "default", ProjectID: "project-1", VPCID: "vpc-1", ID: id}} - }) - - defer patches.Reset() - - type args struct { - obj *v1alpha2.IPPool - subnetRequest *v1alpha2.SubnetRequest - } - tests := []struct { - name string - args args - want string - wantErr assert.ErrorAssertionFunc - }{ - {"1", args{obj: &v1alpha2.IPPool{}, subnetRequest: &v1alpha2.SubnetRequest{}}, "1.1.1.1/24", assert.NoError}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ipPoolService.acquireCidr(tt.args.obj, tt.args.subnetRequest, 3) - if !tt.wantErr(t, err, fmt.Sprintf("acquireCidr(%v, %v)", tt.args.obj, tt.args.subnetRequest)) { - return - } - assert.Equalf(t, tt.want, got, "acquireCidr(%v, %v)", tt.args.obj, tt.args.subnetRequest) - }) - } -} - -func TestIPPoolService_DeleteIPPool(t *testing.T) { - service := fakeService() - iap := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - iapbs := []*model.IpAddressPoolBlockSubnet{ - {Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}}} - - patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "BuildIPPool", func(service *IPPoolService, IPPool *v1alpha2.IPPool) (*model. - IpAddressPool, - []*model.IpAddressPoolBlockSubnet) { - return iap, iapbs - }) - patch.ApplyMethod(reflect.TypeOf(service), "Apply", func(service *IPPoolService, nsxIPPool *model.IpAddressPool, - nsxIPSubnets []*model.IpAddressPoolBlockSubnet, IPPoolUpdated bool, IPPoolSubnetsUpdated bool) error { - return nil - }) - defer patch.Reset() - - ipPool := &v1alpha2.IPPool{} - - t.Run("1", func(t *testing.T) { - err := service.DeleteIPPool(ipPool) - assert.NoError(t, err, "DeleteIPPool(%v)", ipPool) - }) -} - -func TestIPPoolService_AcquireRealizedSubnetIP(t *testing.T) { - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: vpcCacheIndexer, - BindingType: model.VpcBindingType(), - } - vpcStore := &vpc.VPCStore{ResourceStore: resourceStore} - ipPoolService := fakeService() - ipPoolService.VPCService = &vpc.VPCService{VpcStore: vpcStore} - patches := gomonkey.ApplyMethod(reflect.TypeOf(ipPoolService.VPCService), "ListVPCInfo", func(_ *vpc.VPCService, ns string) []common.VPCResourceInfo { - id := "vpc-1" - return []common.VPCResourceInfo{{OrgID: "default", ProjectID: "project-1", VPCID: "vpc-1", ID: id}} - }) - defer patches.Reset() - ipPool2 := &v1alpha2.IPPool{ - Spec: v1alpha2.IPPoolSpec{ - Subnets: []v1alpha2.SubnetRequest{ - { - Name: "subnet1", - }, - }, - }, - Status: v1alpha2.IPPoolStatus{ - Subnets: []v1alpha2.SubnetResult{ - { - Name: "subnet1", - }, - }, - }, - } - - result := []v1alpha2.SubnetResult{ - { - Name: "subnet1", - CIDR: "1.1.1.1/24", - }, - } - - t.Run("1", func(t *testing.T) { - got, got1, err := ipPoolService.AcquireRealizedSubnetIP(ipPool2) - assert.NoError(t, err, "AcquireRealizedSubnetIP(%v)", ipPool2) - assert.Equalf(t, result, got, "AcquireRealizedSubnetIP(%v)", ipPool2) - assert.Equalf(t, true, got1, "AcquireRealizedSubnetIP(%v)", ipPool2) - }) -} - -func TestIPPoolService_CRUDResource(t *testing.T) { - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: vpcCacheIndexer, - BindingType: model.VpcBindingType(), - } - vpcStore := &vpc.VPCStore{ResourceStore: resourceStore} - service := fakeService() - service.VPCService = &vpc.VPCService{VpcStore: vpcStore} - patches := gomonkey.ApplyMethod(reflect.TypeOf(service.VPCService), "ListVPCInfo", func(_ *vpc.VPCService, ns string) []common.VPCResourceInfo { - id := "vpc-1" - return []common.VPCResourceInfo{{OrgID: "default", ProjectID: "project-1", VPCID: "vpc-1", ID: id}} - }) - defer patches.Reset() - iap := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - iapbs := []*model.IpAddressPoolBlockSubnet{ - {Id: String("1"), DisplayName: String("1"), Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), Tag: String("1")}}}} - - ipPoolStore := &IPPoolStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBindingType(), - }} - ipPoolBlockSubnetStore := &IPPoolBlockSubnetStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBlockSubnetBindingType(), - }} - patch := gomonkey.ApplyMethod(reflect.TypeOf(ipPoolStore), "Apply", func(_ *IPPoolStore, nsxIPPool interface{}) error { - return nil - }) - patch.ApplyMethod(reflect.TypeOf(ipPoolBlockSubnetStore), "Apply", func(_ *IPPoolBlockSubnetStore, _ interface{}) error { - return nil - }) - defer patch.Reset() - - t.Run("1", func(t *testing.T) { - err := service.Apply(iap, iapbs, true, true) - assert.NoError(t, err, "Apply(%v)(%v)", iap, iapbs) - }) -} - -func TestIPPoolService_CreateOrUpdateIPPool(t *testing.T) { - service := fakeService() - ipPool2 := &v1alpha2.IPPool{ - Spec: v1alpha2.IPPoolSpec{ - Subnets: []v1alpha2.SubnetRequest{ - { - Name: "subnet1", - }, - }, - Type: common.IPPoolTypePrivate, - }, - Status: v1alpha2.IPPoolStatus{ - Subnets: []v1alpha2.SubnetResult{ - { - Name: "subnet1", - }, - }, - }, - } - - var vpcinfolist = []common.VPCResourceInfo{ - {OrgID: "1", VPCID: "1", ProjectID: "1", ID: "1", ParentID: "1"}, - } - service.VPCService = &vpc.VPCService{} - patch := gomonkey.ApplyMethod(reflect.TypeOf(service.VPCService), "ListVPCInfo", func(vpcService common.VPCServiceProvider, - ns string) []common.VPCResourceInfo { - return vpcinfolist - }) - defer patch.Reset() - - p := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - ipPoolStore := &IPPoolStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBindingType(), - }} - ipPoolStore.Apply(p) - - iapbs := []*model.IpAddressPoolBlockSubnet{ - {Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}}} - ipPoolBlockSubnetStore := &IPPoolBlockSubnetStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBlockSubnetBindingType(), - }} - ipPoolBlockSubnetStore.Apply(iapbs) - var vpcinfo = []common.VPCResourceInfo{ - {PrivateIpv4Blocks: []string{"/infra/ip-blocks/block-test"}}, - } - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: vpcCacheIndexer, - BindingType: model.VpcBindingType(), - } - vpcStore := &vpc.VPCStore{ResourceStore: resourceStore} - service.VPCService = &vpc.VPCService{VpcStore: vpcStore} - patch = gomonkey.ApplyMethod(reflect.TypeOf(service.VPCService), "ListVPCInfo", func(vpcService *vpc.VPCService, - ns string) []common.VPCResourceInfo { - return vpcinfo - }) - defer patch.Reset() - t.Run("1", func(t *testing.T) { - got, got1, err := service.CreateOrUpdateIPPool(ipPool2) - assert.NoError(t, err, "CreateOrUpdateIPPool(%v)(%v)", got, got1) - }) -} - -func TestInitializeIPPool(t *testing.T) { - service := fakeService() - wg := sync.WaitGroup{} - fatalErrors := make(chan error) - wg.Add(3) - - var tc *bindings.TypeConverter - patches2 := gomonkey.ApplyMethod(reflect.TypeOf(tc), "ConvertToGolang", - func(_ *bindings.TypeConverter, d data.DataValue, b bindings.BindingType) (m interface{}, err []error) { - mId, mTag, mScope := "11111", "11111", "11111" - m = model.IpAddressPool{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - err = nil - return - }) - defer patches2.Reset() - - service.InitializeResourceStore(&wg, fatalErrors, ResourceTypeIPPool, nil, service.ipPoolStore) - assert.Empty(t, fatalErrors) - assert.Equal(t, []string{"11111"}, service.ipPoolStore.ListKeys()) -} diff --git a/pkg/nsx/services/ippool/parse.go b/pkg/nsx/services/ippool/parse.go deleted file mode 100644 index 8dde41d89..000000000 --- a/pkg/nsx/services/ippool/parse.go +++ /dev/null @@ -1,30 +0,0 @@ -package ippool - -import ( - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" -) - -func (service *IPPoolService) GetUnrealizedSubnetNames(obj *v1alpha2.IPPool) []string { - var unrealizedSubnets []string - for _, subnetRequest := range obj.Spec.Subnets { - realized := false - for _, statusSubnet := range obj.Status.Subnets { - if statusSubnet.Name == subnetRequest.Name && statusSubnet.CIDR != "" { - realized = true - break - } - } - if !realized { - unrealizedSubnets = append(unrealizedSubnets, subnetRequest.Name) - } - } - return unrealizedSubnets -} - -func (service *IPPoolService) FullyRealized(obj *v1alpha2.IPPool) bool { - return len(service.GetUnrealizedSubnetNames(obj)) == 0 -} - -func getCluster(service *IPPoolService) string { - return service.NSXConfig.Cluster -} diff --git a/pkg/nsx/services/ippool/parse_test.go b/pkg/nsx/services/ippool/parse_test.go deleted file mode 100644 index 0e04e140a..000000000 --- a/pkg/nsx/services/ippool/parse_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package ippool - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" -) - -func TestIPPoolService_FullyRealized(t *testing.T) { - ipPoolService := fakeService() - ipPool := &v1alpha2.IPPool{ - Spec: v1alpha2.IPPoolSpec{ - Subnets: []v1alpha2.SubnetRequest{ - { - Name: "subnet1", - }, - }, - }, - Status: v1alpha2.IPPoolStatus{ - Subnets: []v1alpha2.SubnetResult{ - { - Name: "subnet1", - CIDR: "1.1.1/24", - }, - }, - }, - } - - ipPool2 := &v1alpha2.IPPool{ - Spec: v1alpha2.IPPoolSpec{ - Subnets: []v1alpha2.SubnetRequest{ - { - Name: "subnet1", - }, - }, - }, - Status: v1alpha2.IPPoolStatus{ - Subnets: []v1alpha2.SubnetResult{ - { - Name: "subnet1", - }, - }, - }, - } - type args struct { - obj *v1alpha2.IPPool - } - tests := []struct { - name string - args args - want bool - }{ - {"fully realized", args{ipPool}, true}, - {"not fully realized", args{ipPool2}, false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, ipPoolService.FullyRealized(tt.args.obj), "FullyRealized(%v)", tt.args.obj) - }) - } -} - -func TestIPPoolService_GetUnrealizedSubnetNames(t *testing.T) { - ipPoolService := fakeService() - - ipPool2 := &v1alpha2.IPPool{ - Spec: v1alpha2.IPPoolSpec{ - Subnets: []v1alpha2.SubnetRequest{ - { - Name: "subnet1", - }, - }, - }, - Status: v1alpha2.IPPoolStatus{ - Subnets: []v1alpha2.SubnetResult{ - { - Name: "subnet1", - }, - }, - }, - } - type args struct { - obj *v1alpha2.IPPool - } - tests := []struct { - name string - args args - want []string - }{ - {"1", args{ipPool2}, []string{"subnet1"}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, ipPoolService.GetUnrealizedSubnetNames(tt.args.obj), "GetUnrealizedSubnetNames(%v)", tt.args.obj) - }) - } -} diff --git a/pkg/nsx/services/ippool/store.go b/pkg/nsx/services/ippool/store.go deleted file mode 100644 index 7a7651147..000000000 --- a/pkg/nsx/services/ippool/store.go +++ /dev/null @@ -1,146 +0,0 @@ -package ippool - -import ( - "errors" - - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "k8s.io/apimachinery/pkg/types" - - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -func keyFunc(obj interface{}) (string, error) { - switch v := obj.(type) { - case *model.IpAddressPool: - return *v.Id, nil - case *model.IpAddressPoolBlockSubnet: - return *v.Id, nil - case *model.GenericPolicyRealizedResource: - return *v.Id, nil - default: - return "", errors.New("keyFunc doesn't support unknown type") - } -} - -func indexFunc(obj interface{}) ([]string, error) { - res := make([]string, 0, 5) - switch v := obj.(type) { - case *model.IpAddressPoolBlockSubnet: - return filterTag(v.Tags), nil - case *model.IpAddressPool: - return filterTag(v.Tags), nil - case *model.GenericPolicyRealizedResource: - return filterTag(v.Tags), nil - default: - return res, errors.New("indexFunc doesn't support unknown type") - } -} - -var filterTag = func(v []model.Tag) []string { - res := make([]string, 0, 5) - for _, tag := range v { - if *tag.Scope == common.TagScopeIPPoolCRUID { - res = append(res, *tag.Tag) - } - } - return res -} - -type IPPoolStore struct { - common.ResourceStore -} - -type IPPoolBlockSubnetStore struct { - common.ResourceStore -} - -func ipPoolAssertion(i interface{}) interface{} { - return i.(model.IpAddressPool) -} - -func ipPoolBlockSubnetAssertion(i interface{}) interface{} { - return i.(model.IpAddressPoolBlockSubnet) -} - -func (ipPoolStore *IPPoolStore) Apply(i interface{}) error { - ipPool := i.(*model.IpAddressPool) - if ipPool.MarkedForDelete != nil && *ipPool.MarkedForDelete { - err := ipPoolStore.Delete(ipPool) - log.V(1).Info("delete ipPool from store", "ipPool", ipPool) - if err != nil { - return err - } - } else { - err := ipPoolStore.Add(ipPool) - log.V(1).Info("add ipPool to store", "ipPool", ipPool) - if err != nil { - return err - } - } - return nil -} - -func (ipPoolBlockSubnetStore *IPPoolBlockSubnetStore) Apply(i interface{}) error { - ipPoolBlockSubnets := i.([]*model.IpAddressPoolBlockSubnet) - for _, ipPoolBlockSubnet := range ipPoolBlockSubnets { - if ipPoolBlockSubnet.MarkedForDelete != nil && *ipPoolBlockSubnet.MarkedForDelete { - err := ipPoolBlockSubnetStore.Delete(ipPoolBlockSubnet) - log.V(1).Info("delete ipPoolBlockSubnet from store", "ipPoolBlockSubnet", ipPoolBlockSubnet) - if err != nil { - return err - } - } else { - err := ipPoolBlockSubnetStore.Add(ipPoolBlockSubnet) - log.V(1).Info("add ipPoolBlockSubnet to store", "ipPoolBlockSubnet", ipPoolBlockSubnet) - if err != nil { - return err - } - } - } - return nil -} - -func (service *IPPoolService) indexedIPPoolAndIPPoolSubnets(uid types.UID) (*model.IpAddressPool, []*model.IpAddressPoolBlockSubnet, error) { - nsxIPPool, err := service.ipPoolStore.GetByIndex(uid) - if err != nil { - return nil, nil, err - } - nsxIPPoolSubnets, err := service.ipPoolBlockSubnetStore.GetByIndex(uid) - if err != nil { - return nil, nil, err - } - return nsxIPPool, nsxIPPoolSubnets, nil -} - -func (ipPoolBlockSubnetStore *IPPoolBlockSubnetStore) GetByIndex(uid types.UID) ([]*model.IpAddressPoolBlockSubnet, error) { - nsxIPSubnets := make([]*model.IpAddressPoolBlockSubnet, 0) - indexResults, err := ipPoolBlockSubnetStore.ResourceStore.ByIndex(common.TagScopeIPPoolCRUID, string(uid)) - if err != nil { - log.Error(err, "failed to get ip subnets", "UID", string(uid)) - return nil, err - } - if len(indexResults) == 0 { - log.Info("did not get ip subnets with index", "UID", string(uid)) - } - for _, ipSubnet := range indexResults { - t := ipSubnet.(*model.IpAddressPoolBlockSubnet) - nsxIPSubnets = append(nsxIPSubnets, t) - } - return nsxIPSubnets, nil -} - -func (ipPoolStore *IPPoolStore) GetByIndex(uid types.UID) (*model.IpAddressPool, error) { - nsxIPPool := &model.IpAddressPool{} - indexResults, err := ipPoolStore.ResourceStore.ByIndex(common.TagScopeIPPoolCRUID, string(uid)) - if err != nil { - log.Error(err, "failed to get ip pool", "UID", string(uid)) - return nil, err - } - if len(indexResults) > 0 { - t := indexResults[0].(*model.IpAddressPool) - nsxIPPool = t - } else { - log.Info("did not get ip pool with index", "UID", string(uid)) - } - return nsxIPPool, nil -} diff --git a/pkg/nsx/services/ippool/store_test.go b/pkg/nsx/services/ippool/store_test.go deleted file mode 100644 index 85fff100c..000000000 --- a/pkg/nsx/services/ippool/store_test.go +++ /dev/null @@ -1,270 +0,0 @@ -package ippool - -import ( - "fmt" - "reflect" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -func TestIPPoolBlockSubnetStore_CRUDResource(t *testing.T) { - ipPoolBlockSubnetCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: ipPoolBlockSubnetCacheIndexer, - BindingType: model.IpAddressPoolBlockSubnetBindingType(), - } - ipPoolBlockSubnetStore := &IPPoolBlockSubnetStore{ResourceStore: resourceStore} - type args struct { - i interface{} - } - tests := []struct { - name string - args args - wantErr assert.ErrorAssertionFunc - }{ - {"1", args{i: []*model.IpAddressPoolBlockSubnet{{Id: String("1")}}}, assert.NoError}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.wantErr(t, ipPoolBlockSubnetStore.Apply(tt.args.i), fmt.Sprintf("Apply(%v)", tt.args.i)) - }) - } -} - -func TestIPPoolStore_GetByIndex(t *testing.T) { - p := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - ipPoolStore := &IPPoolStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBindingType(), - }} - ipPoolStore.Apply(p) - type args struct { - uid types.UID - } - tests := []struct { - name string - args args - want *model.IpAddressPool - wantErr bool - }{ - {"1", args{uid: "1"}, &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), Tag: String("1")}}}, false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ipPoolStore.GetByIndex(tt.args.uid) - if (err != nil) != tt.wantErr { - t.Errorf("indexedIPPool() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("indexedIPPool() got = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIPPoolBlockSubnetStore_GetByIndex(t *testing.T) { - p := []*model.IpAddressPoolBlockSubnet{ - {Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}}} - ipPoolBlockSubnetStore := &IPPoolBlockSubnetStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}), - BindingType: model.IpAddressPoolBlockSubnetBindingType(), - }} - ipPoolBlockSubnetStore.Apply(p) - type args struct { - uid types.UID - } - tests := []struct { - name string - args args - want []*model.IpAddressPoolBlockSubnet - wantErr bool - }{ - {"1", args{uid: "1"}, []*model.IpAddressPoolBlockSubnet{{Id: String("1"), DisplayName: String("1"), Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), Tag: String("1")}}}}, false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ipPoolBlockSubnetStore.GetByIndex(tt.args.uid) - if (err != nil) != tt.wantErr { - t.Errorf("indexedIPPoolSubnets() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("indexedIPPoolSubnets() got = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIPPoolStore_CRUDResource(t *testing.T) { - ipPoolCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPPoolCRUID: indexFunc}) - resourceStore := common.ResourceStore{ - Indexer: ipPoolCacheIndexer, - BindingType: model.IpAddressPoolBindingType(), - } - ipPoolStore := &IPPoolStore{ResourceStore: resourceStore} - type args struct { - i interface{} - } - tests := []struct { - name string - args args - wantErr assert.ErrorAssertionFunc - }{ - {"1", args{i: &model.IpAddressPool{Id: String("1")}}, assert.NoError}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.wantErr(t, ipPoolStore.Apply(tt.args.i), fmt.Sprintf("Apply(%v)", tt.args.i)) - }) - } -} - -func Test_indexFunc(t *testing.T) { - mId, mTag, mScope := "11111", "11111", common.TagScopeIPPoolCRUID - m := &model.IpAddressPool{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - r := &model.IpAddressPoolBlockSubnet{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - t.Run("1", func(t *testing.T) { - got, _ := indexFunc(m) - if !reflect.DeepEqual(got, []string{"11111"}) { - t.Errorf("indexFunc() = %v, want %v", got, model.Tag{Tag: &mTag, Scope: &mScope}) - } - }) - t.Run("2", func(t *testing.T) { - got, _ := indexFunc(r) - if !reflect.DeepEqual(got, []string{"11111"}) { - t.Errorf("indexFunc() = %v, want %v", got, model.Tag{Tag: &mTag, Scope: &mScope}) - } - }) -} - -func Test_ipPoolAssertion(t *testing.T) { - mId, mTag, mScope := "11111", "11111", common.TagScopeIPPoolCRUID - m := model.IpAddressPool{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - type args struct { - i interface{} - } - tests := []struct { - name string - args args - want interface{} - }{ - {"1", args{i: m}, m}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ipPoolAssertion(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("ipPoolAssertion() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_ipPoolBlockSubnetAssertion(t *testing.T) { - mId, mTag, mScope := "11111", "11111", common.TagScopeIPPoolCRUID - r := model.IpAddressPoolBlockSubnet{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - type args struct { - i interface{} - } - tests := []struct { - name string - args args - want interface{} - }{ - {"1", args{i: r}, r}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ipPoolBlockSubnetAssertion(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("ipPoolBlockSubnetAssertion() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_keyFunc(t *testing.T) { - Id := "11111" - g := &model.IpAddressPool{Id: &Id} - s := &model.IpAddressPoolBlockSubnet{Id: &Id} - t.Run("1", func(t *testing.T) { - got, _ := keyFunc(s) - if got != "11111" { - t.Errorf("keyFunc() = %v, want %v", got, "11111") - } - }) - t.Run("2", func(t *testing.T) { - got, _ := keyFunc(g) - if got != "11111" { - t.Errorf("keyFunc() = %v, want %v", got, "11111") - } - }) -} - -func TestIPPoolService_indexedIPPoolAndIPPoolSubnets1(t *testing.T) { - ipPoolService := fakeService() - p := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - ipPoolService.ipPoolStore.Apply(p) - - iapbs := []*model.IpAddressPoolBlockSubnet{ - {Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}}} - ipPoolService.ipPoolBlockSubnetStore.Apply(iapbs) - - type args struct { - uid types.UID - } - tests := []struct { - name string - args args - want []*model.IpAddressPoolBlockSubnet - want2 *model.IpAddressPool - wantErr bool - }{ - { - "1", - args{uid: "1"}, - []*model.IpAddressPoolBlockSubnet{{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), Tag: String("1")}}}}, - &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), Tag: String("1")}}}, - false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, got2, _ := ipPoolService.indexedIPPoolAndIPPoolSubnets(tt.args.uid) - if !reflect.DeepEqual(got, tt.want2) { - t.Errorf("indexedIPPool() got = %v, want %v", got, tt.want) - } - if !reflect.DeepEqual(got2, tt.want) { - t.Errorf("indexedIPPoolSubnets() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/nsx/services/ippool/wrap.go b/pkg/nsx/services/ippool/wrap.go deleted file mode 100644 index 62cc2d62e..000000000 --- a/pkg/nsx/services/ippool/wrap.go +++ /dev/null @@ -1,80 +0,0 @@ -package ippool - -import ( - "github.com/openlyinc/pointy" - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -func (service *IPPoolService) WrapHierarchyIPPool(iap *model.IpAddressPool, iapbs []*model.IpAddressPoolBlockSubnet) (*model.Infra, error) { - IPSubnetsChildren, err := service.wrapIPSubnets(iapbs) - if err != nil { - return nil, err - } - iap.Children = IPSubnetsChildren - IPPoolChildren, err := service.wrapIPPool(iap) - if err != nil { - return nil, err - } - var infraChildren []*data.StructValue - infraChildren = append(infraChildren, IPPoolChildren...) - - infra, err := service.wrapInfra(infraChildren) - if err != nil { - return nil, err - } - return infra, nil -} - -func (service *IPPoolService) wrapInfra(children []*data.StructValue) (*model.Infra, error) { - // This is the outermost layer of the hierarchy security policy. - // It doesn't need ID field. - infraType := "Infra" - infraObj := model.Infra{ - Children: children, - ResourceType: &infraType, - } - return &infraObj, nil -} - -func (service *IPPoolService) wrapIPSubnets(IPSubnets []*model.IpAddressPoolBlockSubnet) ([]*data.StructValue, error) { - var IPSubnetsChildren []*data.StructValue - for _, IPSubnet := range IPSubnets { - IPSubnet.ResourceType = common.ResourceTypeIPPoolBlockSubnet - dataValue, errs := NewConverter().ConvertToVapi(IPSubnet, model.IpAddressPoolBlockSubnetBindingType()) - if len(errs) > 0 { - return nil, errs[0] - } - childIPSubnet := model.ChildIpAddressPoolSubnet{ - ResourceType: "ChildIpAddressPoolSubnet", - Id: IPSubnet.Id, - MarkedForDelete: IPSubnet.MarkedForDelete, - IpAddressPoolSubnet: dataValue.(*data.StructValue), - } - dataValue, errs = NewConverter().ConvertToVapi(childIPSubnet, model.ChildIpAddressPoolSubnetBindingType()) - if len(errs) > 0 { - return nil, errs[0] - } - IPSubnetsChildren = append(IPSubnetsChildren, dataValue.(*data.StructValue)) - } - return IPSubnetsChildren, nil -} - -func (service *IPPoolService) wrapIPPool(iap *model.IpAddressPool) ([]*data.StructValue, error) { - var IPPoolChildren []*data.StructValue - iap.ResourceType = pointy.String(common.ResourceTypeIPPool) - childIPool := model.ChildIpAddressPool{ - Id: iap.Id, - MarkedForDelete: iap.MarkedForDelete, - ResourceType: "ChildIpAddressPool", - IpAddressPool: iap, - } - dataValue, errs := NewConverter().ConvertToVapi(childIPool, model.ChildIpAddressPoolBindingType()) - if len(errs) > 0 { - return nil, errs[0] - } - IPPoolChildren = append(IPPoolChildren, dataValue.(*data.StructValue)) - return IPPoolChildren, nil -} diff --git a/pkg/nsx/services/ippool/wrap_test.go b/pkg/nsx/services/ippool/wrap_test.go deleted file mode 100644 index f133a9c58..000000000 --- a/pkg/nsx/services/ippool/wrap_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package ippool - -import ( - "testing" - - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -func TestIPPoolService_WrapHierarchyIPPool(t *testing.T) { - service := fakeService() - iapbs := []*model.IpAddressPoolBlockSubnet{ - { - Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), Tag: String("1")}}}} - iap := &model.IpAddressPool{Id: String("1"), DisplayName: String("1"), - Tags: []model.Tag{{Scope: String(common.TagScopeIPPoolCRUID), - Tag: String("1")}}} - - tests := []struct { - name string - want []*data.StructValue - wantErr bool - }{ - {"1", nil, false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := service.WrapHierarchyIPPool(iap, iapbs) - if (err != nil) != tt.wantErr { - t.Errorf("WrapHierarchyIPPool() error = %v, wantErr %v", err, tt.wantErr) - return - } - }) - } -} diff --git a/pkg/nsx/services/node/node.go b/pkg/nsx/services/node/node.go index 91ca4726e..7d66d7582 100644 --- a/pkg/nsx/services/node/node.go +++ b/pkg/nsx/services/node/node.go @@ -9,10 +9,11 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/logger" servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" ) var ( - log = logger.Log + log = &logger.Log ResourceTypeNode = servicecommon.ResourceTypeNode MarkedForDelete = true ) @@ -74,7 +75,7 @@ func (service *NodeService) SyncNodeStore(nodeName string, deleted bool) error { } // TODO: confirm whether we need to resync the node info from NSX if len(nodes) == 1 { - log.Info("node alreay cached", "node.Fqdn", nodes[0].NodeDeploymentInfo.Fqdn, "node.Id", *nodes[0].Id) + log.Info("node alreay cached", "node.Fqdn", nodes[0].NodeDeploymentInfo.Fqdn, "node.UniqueId", *nodes[0].UniqueId) // updatedNode, err := service.NSXClient.HostTransPortNodesClient.Get("default", "default", nodes[0].Id) // if err != nil { // return fmt.Errorf("failed to get HostTransPortNode for node %s: %s", nodeName, err) @@ -82,6 +83,7 @@ func (service *NodeService) SyncNodeStore(nodeName string, deleted bool) error { // node.NodeStore.Apply(updatedNode) } nodeResults, err := service.NSXClient.HostTransPortNodesClient.List("default", "default", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { return fmt.Errorf("failed to list HostTransportNodes: %s", err) } diff --git a/pkg/nsx/services/node/store.go b/pkg/nsx/services/node/store.go index 70648ca03..6327fbd9c 100644 --- a/pkg/nsx/services/node/store.go +++ b/pkg/nsx/services/node/store.go @@ -56,7 +56,7 @@ func (nodeStore *NodeStore) GetByIndex(key string, value string) []*model.HostTr func keyFunc(obj interface{}) (string, error) { switch v := obj.(type) { case *model.HostTransportNode: - return *v.Id, nil + return *v.UniqueId, nil default: return "", errors.New("keyFunc doesn't support unknown type") } diff --git a/pkg/nsx/services/node/store_test.go b/pkg/nsx/services/node/store_test.go index 7538a81f1..99a73683d 100644 --- a/pkg/nsx/services/node/store_test.go +++ b/pkg/nsx/services/node/store_test.go @@ -13,7 +13,7 @@ import ( func Test_KeyFunc(t *testing.T) { id := "test_id" - node := model.HostTransportNode{Id: &id} + node := model.HostTransportNode{UniqueId: &id} t.Run("1", func(t *testing.T) { got, _ := keyFunc(&node) if got != "test_id" { @@ -34,7 +34,7 @@ func TestSubnetStore_Apply(t *testing.T) { } nodeStore := &NodeStore{ResourceStore: resourceStore} fakeNode := model.HostTransportNode{ - Id: common.String("node_id"), + UniqueId: common.String("node_id"), NodeDeploymentInfo: &model.FabricHostNode{ Fqdn: common.String("node_name"), }, diff --git a/pkg/nsx/services/nsxserviceaccount/builder.go b/pkg/nsx/services/nsxserviceaccount/builder.go index 0f66a4a0b..61b489dd4 100644 --- a/pkg/nsx/services/nsxserviceaccount/builder.go +++ b/pkg/nsx/services/nsxserviceaccount/builder.go @@ -6,7 +6,7 @@ package nsxserviceaccount import ( "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) diff --git a/pkg/nsx/services/nsxserviceaccount/cluster.go b/pkg/nsx/services/nsxserviceaccount/cluster.go index 8cae00213..4a933c737 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster.go @@ -22,10 +22,11 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) @@ -43,7 +44,7 @@ const ( ) var ( - log = logger.Log + log = &logger.Log isProtectedTrue = true vpcRole = "ccp_internal_operator" @@ -191,6 +192,7 @@ func (s *NSXServiceAccountService) RestoreRealizedNSXServiceAccount(ctx context. return fmt.Errorf("PI/CCP doesn't match") } _, err := s.NSXClient.ClusterControlPlanesClient.Get(siteId, enforcementpointId, normalizedClusterName) + err = nsxutil.NSXApiError(err) if err == nil { return fmt.Errorf("CCP store is not synchronized") } @@ -240,10 +242,11 @@ func (s *NSXServiceAccountService) createPIAndCCP(normalizedClusterName string, CertificatePem: &cert, Tags: common.ConvertTagsToMPTags(s.buildBasicTags(obj)), }) + err = nsxutil.NSXApiError(err) if err != nil { return "", err } - s.PrincipalIdentityStore.Add(pi) + s.PrincipalIdentityStore.Add(&pi) } else if !hasPI != (piObj == nil) { return "", fmt.Errorf("old PI exists") } @@ -260,10 +263,11 @@ func (s *NSXServiceAccountService) createPIAndCCP(normalizedClusterName string, NodeId: existingClusterId, Tags: s.buildBasicTags(obj), }) + err = nsxutil.NSXApiError(err) if err != nil { return "", err } - s.ClusterControlPlaneStore.Add(ccp) + s.ClusterControlPlaneStore.Add(&ccp) clusterId = *ccp.NodeId } else if !hasCCP != (ccpObj == nil) { return "", fmt.Errorf("old CCP exists") @@ -332,21 +336,24 @@ func (s *NSXServiceAccountService) DeleteNSXServiceAccount(ctx context.Context, if isDeleteCCP { cascade := true if err := s.NSXClient.ClusterControlPlanesClient.Delete(siteId, enforcementpointId, normalizedClusterName, &cascade); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "ClusterControlPlane", normalizedClusterName) return err } - s.ClusterControlPlaneStore.Delete(model.ClusterControlPlane{Id: &normalizedClusterName}) + s.ClusterControlPlaneStore.Delete(&model.ClusterControlPlane{Id: &normalizedClusterName}) } // delete PI if piobj := s.PrincipalIdentityStore.GetByKey(normalizedClusterName); isDeletePI && (piobj != nil) { - pi := piobj.(mpmodel.PrincipalIdentity) + pi := piobj.(*mpmodel.PrincipalIdentity) if err := s.NSXClient.PrincipalIdentitiesClient.Delete(*pi.Id); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name) return err } if pi.CertificateId != nil && *pi.CertificateId != "" { if err := s.NSXClient.CertificatesClient.Delete(*pi.CertificateId); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name, "Certificate", *pi.CertificateId) return err } @@ -430,16 +437,18 @@ func (s *NSXServiceAccountService) updatePIAndCCPCert(normalizedClusterName, uid } // update ClusterControlPlane cert - ccp := ccpObj.(model.ClusterControlPlane) + ccp := ccpObj.(*model.ClusterControlPlane) ccp.Certificate = &cert - if ccp, err := s.NSXClient.ClusterControlPlanesClient.Update(siteId, enforcementpointId, normalizedClusterName, ccp); err != nil { + if ccp2, err := s.NSXClient.ClusterControlPlanesClient.Update(siteId, enforcementpointId, normalizedClusterName, *ccp); err != nil { + err = nsxutil.NSXApiError(err) return err } else { + ccp = &ccp2 s.ClusterControlPlaneStore.Add(ccp) } // update PI cert - pi := piObj.(mpmodel.PrincipalIdentity) + pi := piObj.(*mpmodel.PrincipalIdentity) oldCertId := "" if pi.CertificateId != nil { oldCertId = *pi.CertificateId @@ -449,18 +458,22 @@ func (s *NSXServiceAccountService) updatePIAndCCPCert(normalizedClusterName, uid PemEncoded: &cert, }) if err != nil { + err = nsxutil.NSXApiError(err) return err } - if pi, err = s.NSXClient.PrincipalIdentitiesClient.Updatecertificate(mpmodel.UpdatePrincipalIdentityCertificateRequest{ + if pi2, err := s.NSXClient.PrincipalIdentitiesClient.Updatecertificate(mpmodel.UpdatePrincipalIdentityCertificateRequest{ CertificateId: certList.Results[0].Id, PrincipalIdentityId: pi.Id, }); err != nil { + err = nsxutil.NSXApiError(err) return err } else { + pi = &pi2 s.PrincipalIdentityStore.Add(pi) } if oldCertId != "" { if err := s.NSXClient.CertificatesClient.Delete(oldCertId); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name, "Old Certificate", *pi.CertificateId) } } @@ -484,7 +497,7 @@ func (s *NSXServiceAccountService) GetNSXServiceAccountNameByUID(uid string) (na return } for _, obj := range objs { - pi := obj.(mpmodel.PrincipalIdentity) + pi := obj.(*mpmodel.PrincipalIdentity) for _, tag := range pi.Tags { switch *tag.Scope { case common.TagScopeNamespace: @@ -503,7 +516,7 @@ func (s *NSXServiceAccountService) GetNSXServiceAccountNameByUID(uid string) (na return } for _, obj := range objs { - ccp := obj.(model.ClusterControlPlane) + ccp := obj.(*model.ClusterControlPlane) for _, tag := range ccp.Tags { if tag.Scope != nil { switch *tag.Scope { diff --git a/pkg/nsx/services/nsxserviceaccount/cluster_test.go b/pkg/nsx/services/nsxserviceaccount/cluster_test.go index 985218534..2730280fc 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster_test.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster_test.go @@ -26,7 +26,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" @@ -551,7 +551,7 @@ func TestNSXServiceAccountService_RestoreRealizedNSXServiceAccount(t *testing.T) vpcPath := "/orgs/default/projects/k8scl-one:test/vpcs/vpc1" piId := "Id1" uid := "00000000-0000-0000-0000-000000000001" - s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ IsProtected: &isProtectedTrue, Name: &normalizedClusterName, NodeId: &normalizedClusterName, @@ -583,7 +583,7 @@ func TestNSXServiceAccountService_RestoreRealizedNSXServiceAccount(t *testing.T) }}, }) nodeId := "clusterId1" - s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &normalizedClusterName, NodeId: &nodeId, Revision: &revision1, @@ -637,7 +637,7 @@ func TestNSXServiceAccountService_RestoreRealizedNSXServiceAccount(t *testing.T) vpcPath := "/orgs/default/projects/k8scl-one:test/vpcs/vpc1" piId := "Id1" uid := "00000000-0000-0000-0000-000000000001" - s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ IsProtected: &isProtectedTrue, Name: &normalizedClusterName, NodeId: &normalizedClusterName, @@ -1130,8 +1130,8 @@ func TestNSXServiceAccountService_ValidateAndUpdateRealizedNSXServiceAccount(t * Scope: &uidScope, Tag: &uidTag, }}} - assert.NoError(t, s.ClusterControlPlaneStore.Add(ccp)) - assert.NoError(t, s.PrincipalIdentityStore.Add(pi)) + assert.NoError(t, s.ClusterControlPlaneStore.Add(&ccp)) + assert.NoError(t, s.PrincipalIdentityStore.Add(&pi)) patches := gomonkey.ApplyMethodSeq(s.NSXClient, "NSXCheckVersion", []gomonkey.OutputCell{{ Values: gomonkey.Params{true}, @@ -1245,8 +1245,8 @@ func TestNSXServiceAccountService_DeleteNSXServiceAccount(t *testing.T) { normalizedClusterName := "k8scl-one_test-ns1-name1" piId := "piId1" certId := "certId1" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{Id: &normalizedClusterName})) - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId})) + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{Id: &normalizedClusterName})) + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId})) assert.NoError(t, s.Client.Create(ctx, &v1alpha1.NSXServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "name1", @@ -1285,8 +1285,8 @@ func TestNSXServiceAccountService_DeleteNSXServiceAccount(t *testing.T) { normalizedClusterName := "k8scl-one_test-ns1-name1" piId := "piId1" certId := "certId1" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{Id: &normalizedClusterName})) - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId, Tags: []mpmodel.Tag{{ + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{Id: &normalizedClusterName})) + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId, Tags: []mpmodel.Tag{{ Scope: &uidScope, Tag: &uidTag, }}})) @@ -1357,7 +1357,7 @@ func TestNSXServiceAccountService_ListNSXServiceAccountRealization(t *testing.T) piName := piKey piId := piKey + "-id" crUID := piKey + "-uid" - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Id: &piId, Name: &piName, Tags: []mpmodel.Tag{{ @@ -1369,7 +1369,7 @@ func TestNSXServiceAccountService_ListNSXServiceAccountRealization(t *testing.T) for _, ccpKey := range tt.ccpKeys { ccpId := ccpKey crUID := ccpKey + "-uid" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &ccpId, Tags: []model.Tag{{ Scope: &tagScopeNSXServiceAccountCRUID, @@ -1448,7 +1448,7 @@ func TestNSXServiceAccountService_GetNSXServiceAccountNameByUID(t *testing.T) { piName := piKey.Namespace + "-" + piKey.Name piId := piName + "-id" crUID := piName + "-uid" - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Id: &piId, Name: &piName, Tags: []mpmodel.Tag{{ @@ -1466,7 +1466,7 @@ func TestNSXServiceAccountService_GetNSXServiceAccountNameByUID(t *testing.T) { for _, ccpKey := range tt.ccpKeys { ccpId := ccpKey.Namespace + "-" + ccpKey.Name crUID := ccpId + "-uid" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &ccpId, Tags: []model.Tag{{ Scope: &tagScopeNamespace, diff --git a/pkg/nsx/services/nsxserviceaccount/store.go b/pkg/nsx/services/nsxserviceaccount/store.go index 66701f1c2..df9719619 100644 --- a/pkg/nsx/services/nsxserviceaccount/store.go +++ b/pkg/nsx/services/nsxserviceaccount/store.go @@ -4,7 +4,8 @@ package nsxserviceaccount import ( - "errors" + "fmt" + "reflect" mpmodel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" @@ -18,14 +19,15 @@ type PrincipalIdentityStore struct { } func (s *PrincipalIdentityStore) Apply(i interface{}) error { - pis := i.(*[]mpmodel.PrincipalIdentity) - for _, pi := range *pis { - // MP resource doesn't have MarkedForDelete tag. - err := s.Add(pi) - log.V(1).Info("add PI to store", "pi", pi) - if err != nil { - return err - } + if i == nil { + return nil + } + pi := i.(*mpmodel.PrincipalIdentity) + // MP resource doesn't have MarkedForDelete tag. + err := s.Add(pi) + log.V(1).Info("add PI to store", "pi", pi) + if err != nil { + return err } return nil } @@ -40,20 +42,21 @@ type ClusterControlPlaneStore struct { } func (s *ClusterControlPlaneStore) Apply(i interface{}) error { - pis := i.(*[]model.ClusterControlPlane) - for _, pi := range *pis { - if pi.MarkedForDelete != nil && *pi.MarkedForDelete { - err := s.Delete(pi) - log.V(1).Info("delete PI from store", "pi", pi) - if err != nil { - return err - } - } else { - err := s.Add(pi) - log.V(1).Info("add PI to store", "pi", pi) - if err != nil { - return err - } + if i == nil { + return nil + } + ccp := i.(*model.ClusterControlPlane) + if ccp.MarkedForDelete != nil && *ccp.MarkedForDelete { + err := s.Delete(ccp) + log.V(1).Info("delete ClusterCP from store", "ClusterCP", ccp) + if err != nil { + return err + } + } else { + err := s.Add(ccp) + log.V(1).Info("add ClusterCP to store", "ClusterCP", ccp) + if err != nil { + return err } } return nil @@ -62,12 +65,12 @@ func (s *ClusterControlPlaneStore) Apply(i interface{}) error { // keyFunc returns the key of the object. func keyFunc(obj interface{}) (string, error) { switch v := obj.(type) { - case model.ClusterControlPlane: + case *model.ClusterControlPlane: return *v.Id, nil - case mpmodel.PrincipalIdentity: + case *mpmodel.PrincipalIdentity: return *v.Name, nil default: - return "", errors.New("keyFunc doesn't support unknown type") + return "", fmt.Errorf("keyFunc doesn't support unknown type %v", reflect.TypeOf(obj)) } } @@ -76,12 +79,12 @@ func keyFunc(obj interface{}) (string, error) { func indexFunc(obj interface{}) ([]string, error) { res := make([]string, 0, 5) switch o := obj.(type) { - case model.ClusterControlPlane: + case *model.ClusterControlPlane: return filterTag(o.Tags), nil - case mpmodel.PrincipalIdentity: + case *mpmodel.PrincipalIdentity: return filterTag(common.ConvertMPTagsToTags(o.Tags)), nil default: - return res, errors.New("indexFunc doesn't support unknown type") + return res, fmt.Errorf("indexFunc doesn't support unknown type %v", reflect.TypeOf(obj)) } } diff --git a/pkg/nsx/services/nsxserviceaccount/store_test.go b/pkg/nsx/services/nsxserviceaccount/store_test.go index c79ab4573..fabe99174 100644 --- a/pkg/nsx/services/nsxserviceaccount/store_test.go +++ b/pkg/nsx/services/nsxserviceaccount/store_test.go @@ -27,8 +27,8 @@ func Test_indexFunc(t *testing.T) { want []string wantErr bool }{ - {"1", args{obj: ccp}, []string{"11111"}, false}, - {"2", args{obj: pi}, []string{"11111"}, false}, + {"1", args{obj: &ccp}, []string{"11111"}, false}, + {"2", args{obj: &pi}, []string{"11111"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -49,6 +49,7 @@ func Test_keyFunc(t *testing.T) { ccp := model.ClusterControlPlane{Id: &Id} pi := mpmodel.PrincipalIdentity{Name: &Id} o := model.UserInfo{} + var o2 *model.UserInfo type args struct { obj interface{} } @@ -58,9 +59,11 @@ func Test_keyFunc(t *testing.T) { want string wantErr bool }{ - {"1", args{obj: ccp}, Id, false}, - {"2", args{obj: pi}, Id, false}, + {"1", args{obj: &ccp}, Id, false}, + {"2", args{obj: &pi}, Id, false}, {"0", args{obj: o}, "", true}, + {"typednil", args{obj: o2}, "", true}, + {"nil", args{obj: nil}, "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/nsx/services/realizestate/realize_state.go b/pkg/nsx/services/realizestate/realize_state.go index 29cd1b02f..bd2567a68 100644 --- a/pkg/nsx/services/realizestate/realize_state.go +++ b/pkg/nsx/services/realizestate/realize_state.go @@ -4,7 +4,6 @@ package realizestate import ( - "errors" "fmt" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" @@ -12,6 +11,7 @@ import ( "k8s.io/client-go/util/retry" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" ) type RealizeStateService struct { @@ -34,6 +34,7 @@ func IsRealizeStateError(err error) bool { // CheckRealizeState allows the caller to check realize status of entityType with retries. // backoff defines the maximum retries and the wait interval between two retries. func (service *RealizeStateService) CheckRealizeState(backoff wait.Backoff, intentPath, entityType string) error { + // TODO, ask NSX if there were multiple realize states could we check only the latest one? vpcInfo, err := common.ParseVPCResourcePath(intentPath) if err != nil { return err @@ -43,17 +44,17 @@ func (service *RealizeStateService) CheckRealizeState(backoff wait.Backoff, inte return !IsRealizeStateError(err) }, func() error { results, err := service.NSXClient.RealizedEntitiesClient.List(vpcInfo.OrgID, vpcInfo.ProjectID, intentPath, nil) + err = nsxutil.NSXApiError(err) if err != nil { return err } for _, result := range results.Results { - if *result.EntityType != entityType { + if entityType != "" && result.EntityType != nil && *result.EntityType != entityType { continue } if *result.State == model.GenericPolicyRealizedResource_STATE_REALIZED { return nil } - return errors.New(*result.State) } return fmt.Errorf("%s not realized", entityType) }) diff --git a/pkg/nsx/services/securitypolicy/builder.go b/pkg/nsx/services/securitypolicy/builder.go index df5b9a5be..b7cef914d 100644 --- a/pkg/nsx/services/securitypolicy/builder.go +++ b/pkg/nsx/services/securitypolicy/builder.go @@ -15,7 +15,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" "github.com/vmware-tanzu/nsx-operator/pkg/util" @@ -38,16 +38,25 @@ var ( Int64 = common.Int64 ) -func (service *SecurityPolicyService) buildecurityPolicyName(obj *v1alpha1.SecurityPolicy, createdFor string) string { +func (service *SecurityPolicyService) buildSecurityPolicyName(obj *v1alpha1.SecurityPolicy, createdFor string) string { + if isVpcEnabled(service) { + // For VPC scenario, we use obj.Name as the NSX resource display name for both SecurityPolicy and NetworkPolicy. + return util.GenerateTruncName(common.MaxNameLength, obj.Name, "", "", "", "") + + } prefix := common.SecurityPolicyPrefix if createdFor != common.ResourceTypeSecurityPolicy { prefix = common.NetworkPolicyPrefix } - nsxSecurityPolicyName := util.GenerateTruncName(common.MaxNameLength, fmt.Sprintf("%s-%s", obj.Namespace, obj.Name), prefix, "", "", "") - return nsxSecurityPolicyName + // For T1 scenario, we use ns-name as the key resource name for SecurityPolicy, it is to be consistent with the + // previous solutions. + return util.GenerateTruncName(common.MaxNameLength, fmt.Sprintf("%s-%s", obj.Namespace, obj.Name), prefix, "", "", "") } -func (service *SecurityPolicyService) buildecurityPolicyID(obj *v1alpha1.SecurityPolicy, createdFor string) string { +func (service *SecurityPolicyService) buildSecurityPolicyID(obj *v1alpha1.SecurityPolicy, createdFor string) string { + if isVpcEnabled(service) { + return util.GenerateIDByObject(obj) + } prefix := common.SecurityPolicyPrefix if createdFor != common.ResourceTypeSecurityPolicy { prefix = common.NetworkPolicyPrefix @@ -66,8 +75,8 @@ func (service *SecurityPolicyService) buildSecurityPolicy(obj *v1alpha1.Security log.V(1).Info("building the model SecurityPolicy from CR SecurityPolicy", "object", *obj) nsxSecurityPolicy := &model.SecurityPolicy{} - nsxSecurityPolicy.Id = String(service.buildecurityPolicyID(obj, createdFor)) - nsxSecurityPolicy.DisplayName = String(service.buildecurityPolicyName(obj, createdFor)) + nsxSecurityPolicy.Id = String(service.buildSecurityPolicyID(obj, createdFor)) + nsxSecurityPolicy.DisplayName = String(service.buildSecurityPolicyName(obj, createdFor)) // TODO: confirm the sequence number: offset nsxSecurityPolicy.SequenceNumber = Int64(int64(obj.Spec.Priority)) @@ -366,16 +375,22 @@ func (service *SecurityPolicyService) buildExpressionsMatchExpression(matchExpre // build appliedTo group ID for both policy and rule levels. func (service *SecurityPolicyService) buildAppliedGroupID(obj *v1alpha1.SecurityPolicy, ruleIdx int, createdFor string) string { - prefix := common.SecurityPolicyPrefix - if createdFor == common.ResourceTypeNetworkPolicy { - prefix = common.NetworkPolicyPrefix + if isVpcEnabled(service) { + suffix := common.TargetGroupSuffix + if ruleIdx != -1 { + suffix = fmt.Sprintf("%d_%s", ruleIdx, suffix) + } + return util.GenerateIDByObjectWithSuffix(obj, suffix) } ruleIdxStr := "" if ruleIdx != -1 { ruleIdxStr = fmt.Sprintf("%d", ruleIdx) } - + prefix := common.SecurityPolicyPrefix + if createdFor == common.ResourceTypeNetworkPolicy { + prefix = common.NetworkPolicyPrefix + } return util.GenerateID(string(obj.UID), prefix, common.TargetGroupSuffix, ruleIdxStr) } @@ -580,15 +595,21 @@ func (service *SecurityPolicyService) buildRuleOutGroup(obj *v1alpha1.SecurityPo } func (service *SecurityPolicyService) buildRuleID(obj *v1alpha1.SecurityPolicy, rule *v1alpha1.SecurityPolicyRule, ruleIdx int, createdFor string) string { + serializedBytes, _ := json.Marshal(rule) + ruleHash := fmt.Sprintf("%s", util.Sha1(string(serializedBytes))) + ruleIdxStr := fmt.Sprintf("%d", ruleIdx) + if isVpcEnabled(service) { + suffix := fmt.Sprintf("%s_%s", ruleIdxStr, ruleHash) + return util.GenerateIDByObjectWithSuffix(obj, suffix) + } prefix := common.SecurityPolicyPrefix if createdFor == common.ResourceTypeNetworkPolicy { prefix = common.NetworkPolicyPrefix } - serializedBytes, _ := json.Marshal(rule) - return util.GenerateID(fmt.Sprintf("%s", obj.UID), prefix, fmt.Sprintf("%s", util.Sha1(string(serializedBytes))), fmt.Sprintf("%d", ruleIdx)) + return util.GenerateID(fmt.Sprintf("%s", obj.UID), prefix, ruleHash, ruleIdxStr) } -func (service *SecurityPolicyService) buildRuleDisplayName(obj *v1alpha1.SecurityPolicy, rule *v1alpha1.SecurityPolicyRule, portIdx, portNumber int, hasNamedport bool, createdFor string) (string, error) { +func (service *SecurityPolicyService) buildRuleDisplayName(rule *v1alpha1.SecurityPolicyRule, portIdx, portNumber int, hasNamedport bool, createdFor string) (string, error) { var ruleName string var suffix string @@ -620,19 +641,19 @@ func (service *SecurityPolicyService) buildRuleDisplayName(obj *v1alpha1.Securit suffix = common.RuleSuffixEgressReject } } - ruleName = service.buildRulePortsString(&rule.Ports, suffix) if len(rule.Name) > 0 { // For the internal security policy rule converted from network policy, skipping to add suffix for the rule name // if it has its own name generated, usually, it's for the internal isolation security policy rule created for network policy. - if createdFor == common.ResourceTypeNetworkPolicy { - ruleName = rule.Name - } else { + ruleName = rule.Name + if createdFor != common.ResourceTypeNetworkPolicy { // If user defines the rule name, the generated NSX security policy rule will also be added with the same suffix: "-direction-action" as building rulePortsString // e.g. input security policy's rule name: sp-rule, // the generated NSX security policy rule name: sp-rule-ingress-allow - ruleName = rule.Name + "-" + suffix + ruleName = ruleName + "-" + suffix } + } else { + ruleName = service.buildRulePortsString(&rule.Ports, suffix) } if !hasNamedport { @@ -728,6 +749,9 @@ func (service *SecurityPolicyService) buildRulePeerGroupID(obj *v1alpha1.Securit if isSource == true { suffix = common.SrcGroupSuffix } + if isVpcEnabled(service) { + return util.GenerateIDByObjectWithSuffix(obj, fmt.Sprintf("%d_%s", ruleIdx, suffix)) + } return util.GenerateID(string(obj.UID), common.SecurityPolicyPrefix, suffix, fmt.Sprintf("%d", ruleIdx)) } @@ -855,7 +879,7 @@ func (service *SecurityPolicyService) buildRulePeerGroup(obj *v1alpha1.SecurityP // Build a nsx share resource in project level nsxShare, err := service.buildProjectShare(obj, &rulePeerGroup, []string{rulePeerGroupPath}, *sharedWith, createdFor) if err != nil { - log.Error(err, "failed to build nsx project share", "ruleGroupName", rulePeerGroupName) + log.Error(err, "failed to build NSX project share", "ruleGroupName", rulePeerGroupName) return nil, "", nil, err } @@ -866,6 +890,10 @@ func (service *SecurityPolicyService) buildRulePeerGroup(obj *v1alpha1.SecurityP return &rulePeerGroup, rulePeerGroupPath, nil, err } +func (service *SecurityPolicyService) buildExpandedRuleId(ruleBaseId string, portIdx int, portAddressIdx int) string { + return fmt.Sprintf("%s_%d_%d", ruleBaseId, portIdx, portAddressIdx) +} + // Build rule basic info, ruleIdx is the index of the rules of security policy, // portIdx is the index of rule's ports, portAddressIdx is the index // of multiple port number if one named port maps to multiple port numbers. @@ -880,13 +908,13 @@ func (service *SecurityPolicyService) buildRuleBasicInfo(obj *v1alpha1.SecurityP if err != nil { return nil, err } - displayName, err := service.buildRuleDisplayName(obj, rule, portIdx, portNumber, hasNamedport, createdFor) + displayName, err := service.buildRuleDisplayName(rule, portIdx, portNumber, hasNamedport, createdFor) if err != nil { log.Error(err, "failed to build rule's display name", "object.UID", obj.UID, "rule", rule, "createdFor", createdFor) } nsxRule := model.Rule{ - Id: String(fmt.Sprintf("%s_%d_%d", service.buildRuleID(obj, rule, ruleIdx, createdFor), portIdx, portAddressIdx)), + Id: String(service.buildExpandedRuleId(service.buildRuleID(obj, rule, ruleIdx, createdFor), portIdx, portAddressIdx)), DisplayName: &displayName, Direction: &ruleDirection, SequenceNumber: Int64(int64(ruleIdx)), @@ -1764,7 +1792,7 @@ func (service *SecurityPolicyService) buildProjectShare(obj *v1alpha1.SecurityPo func (service *SecurityPolicyService) buildSharedWith(sharedNamespace *[]string) (*[]string, error) { var sharedWith []string for _, ns := range *sharedNamespace { - log.V(1).Info("building sharedwith in nameSpace", "sharedNamespace", ns) + log.V(1).Info("building shared with in Namespace", "sharedNamespace", ns) vpcInfo, err := service.getVpcInfo(ns) if err != nil { diff --git a/pkg/nsx/services/securitypolicy/builder_test.go b/pkg/nsx/services/securitypolicy/builder_test.go index e32c2c50d..005e3dead 100644 --- a/pkg/nsx/services/securitypolicy/builder_test.go +++ b/pkg/nsx/services/securitypolicy/builder_test.go @@ -3,6 +3,7 @@ package securitypolicy import ( "fmt" "reflect" + "strings" "testing" gomonkey "github.com/agiledragon/gomonkey/v2" @@ -13,7 +14,8 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) @@ -32,18 +34,18 @@ func TestBuildSecurityPolicy(t *testing.T) { }, ) - podSelectorRule0IDPort000 := fmt.Sprintf("%s_%d_%d", service.buildRuleID(&spWithPodSelector, &spWithPodSelector.Spec.Rules[0], 0, common.ResourceTypeSecurityPolicy), 0, 0) - podSelectorRule1IDPort000 := fmt.Sprintf("%s_%d_%d", service.buildRuleID(&spWithPodSelector, &spWithPodSelector.Spec.Rules[1], 1, common.ResourceTypeSecurityPolicy), 0, 0) - vmSelectorRule0IDPort000 := fmt.Sprintf("%s_%d_%d", service.buildRuleID(&spWithVMSelector, &spWithVMSelector.Spec.Rules[0], 0, common.ResourceTypeSecurityPolicy), 0, 0) - vmSelectorRule1IDPort000 := fmt.Sprintf("%s_%d_%d", service.buildRuleID(&spWithVMSelector, &spWithVMSelector.Spec.Rules[1], 1, common.ResourceTypeSecurityPolicy), 0, 0) - vmSelectorRule2IDPort000 := fmt.Sprintf("%s_%d_%d", service.buildRuleID(&spWithVMSelector, &spWithVMSelector.Spec.Rules[2], 2, common.ResourceTypeSecurityPolicy), 0, 0) + podSelectorRule0IDPort000 := service.buildExpandedRuleId(service.buildRuleID(&spWithPodSelector, &spWithPodSelector.Spec.Rules[0], 0, common.ResourceTypeSecurityPolicy), 0, 0) + podSelectorRule1IDPort000 := service.buildExpandedRuleId(service.buildRuleID(&spWithPodSelector, &spWithPodSelector.Spec.Rules[1], 1, common.ResourceTypeSecurityPolicy), 0, 0) + vmSelectorRule0IDPort000 := service.buildExpandedRuleId(service.buildRuleID(&spWithVMSelector, &spWithVMSelector.Spec.Rules[0], 0, common.ResourceTypeSecurityPolicy), 0, 0) + vmSelectorRule1IDPort000 := service.buildExpandedRuleId(service.buildRuleID(&spWithVMSelector, &spWithVMSelector.Spec.Rules[1], 1, common.ResourceTypeSecurityPolicy), 0, 0) + vmSelectorRule2IDPort000 := service.buildExpandedRuleId(service.buildRuleID(&spWithVMSelector, &spWithVMSelector.Spec.Rules[2], 2, common.ResourceTypeSecurityPolicy), 0, 0) - podSelectorRule0Name00, _ := service.buildRuleDisplayName(&spWithPodSelector, &spWithPodSelector.Spec.Rules[0], 0, -1, false, common.ResourceTypeSecurityPolicy) - podSelectorRule1Name00, _ := service.buildRuleDisplayName(&spWithPodSelector, &spWithPodSelector.Spec.Rules[1], 0, -1, false, common.ResourceTypeSecurityPolicy) + podSelectorRule0Name00, _ := service.buildRuleDisplayName(&spWithPodSelector.Spec.Rules[0], 0, -1, false, common.ResourceTypeSecurityPolicy) + podSelectorRule1Name00, _ := service.buildRuleDisplayName(&spWithPodSelector.Spec.Rules[1], 0, -1, false, common.ResourceTypeSecurityPolicy) - vmSelectorRule0Name00, _ := service.buildRuleDisplayName(&spWithVMSelector, &spWithVMSelector.Spec.Rules[0], 0, -1, false, common.ResourceTypeSecurityPolicy) - vmSelectorRule1Name00, _ := service.buildRuleDisplayName(&spWithVMSelector, &spWithVMSelector.Spec.Rules[1], 0, -1, false, common.ResourceTypeSecurityPolicy) - vmSelectorRule2Name00, _ := service.buildRuleDisplayName(&spWithVMSelector, &spWithVMSelector.Spec.Rules[2], 0, -1, false, common.ResourceTypeSecurityPolicy) + vmSelectorRule0Name00, _ := service.buildRuleDisplayName(&spWithVMSelector.Spec.Rules[0], 0, -1, false, common.ResourceTypeSecurityPolicy) + vmSelectorRule1Name00, _ := service.buildRuleDisplayName(&spWithVMSelector.Spec.Rules[1], 0, -1, false, common.ResourceTypeSecurityPolicy) + vmSelectorRule2Name00, _ := service.buildRuleDisplayName(&spWithVMSelector.Spec.Rules[2], 0, -1, false, common.ResourceTypeSecurityPolicy) tests := []struct { name string @@ -801,9 +803,236 @@ func TestBuildRuleDisplayName(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - observedDisplayName, observedError := service.buildRuleDisplayName(tt.inputSecurityPolicy, tt.inputRule, tt.portIdx, -1, false, tt.createdFor) + observedDisplayName, observedError := service.buildRuleDisplayName(tt.inputRule, tt.portIdx, -1, false, tt.createdFor) assert.Equal(t, tt.expectedRuleDisplayName, observedDisplayName) assert.Equal(t, nil, observedError) }) } } + +func TestBuildSecurityPolicyName(t *testing.T) { + svc := &SecurityPolicyService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "cluster1", + }, + }, + }, + } + + for _, tc := range []struct { + name string + vpcEnabled bool + obj *v1alpha1.SecurityPolicy + createdFor string + expName string + expId string + }{ + { + name: "SecurityPolicy with VPC disabled", + vpcEnabled: false, + obj: &v1alpha1.SecurityPolicy{ + ObjectMeta: v1.ObjectMeta{ + UID: "uid1", + Name: "securitypolicy1", + Namespace: "ns1", + }, + }, + createdFor: common.ResourceTypeSecurityPolicy, + expName: "sp-ns1-securitypolicy1", + expId: "sp_uid1", + }, + { + name: "SecurityPolicy with VPC enabled", + vpcEnabled: true, + obj: &v1alpha1.SecurityPolicy{ + ObjectMeta: v1.ObjectMeta{ + UID: "uid2", + Name: "securitypolicy2", + Namespace: "ns2", + }, + }, + createdFor: common.ResourceTypeSecurityPolicy, + expName: "securitypolicy2", + expId: "securitypolicy2-uid2", + }, + { + name: "NetworkPolicy with VPC enabled", + vpcEnabled: true, + obj: &v1alpha1.SecurityPolicy{ + ObjectMeta: v1.ObjectMeta{ + UID: "uid3", + Name: "networkpolicy1", + Namespace: "ns3", + }, + }, + createdFor: common.ResourceTypeNetworkPolicy, + expName: "networkpolicy1", + expId: "networkpolicy1-uid3", + }, + { + name: "NetworkPolicy with VPC enabled with name truncated", + vpcEnabled: true, + obj: &v1alpha1.SecurityPolicy{ + ObjectMeta: v1.ObjectMeta{ + UID: "67c80acd-019a4886-44ce-11ef-b87a-4a38b420eaae", + Name: strings.Repeat("a", 260), + Namespace: strings.Repeat("b", 110), + }, + }, + createdFor: common.ResourceTypeNetworkPolicy, + expName: fmt.Sprintf("%s-c64163f0", strings.Repeat("a", 246)), + expId: fmt.Sprintf("%s-fb85d834", strings.Repeat("a", 246)), + }, + } { + t.Run(tc.name, func(t *testing.T) { + svc.NSXConfig.EnableVPCNetwork = tc.vpcEnabled + name := svc.buildSecurityPolicyName(tc.obj, tc.createdFor) + assert.Equal(t, tc.expName, name) + assert.True(t, len(name) <= common.MaxNameLength) + id := svc.buildSecurityPolicyID(tc.obj, tc.createdFor) + assert.Equal(t, tc.expId, id) + }) + } +} + +func TestBuildGroupName(t *testing.T) { + svc := &SecurityPolicyService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "cluster1", + }, + }, + }, + } + + obj := &v1alpha1.SecurityPolicy{ + ObjectMeta: v1.ObjectMeta{ + UID: "c5db1800-ce4c-11de-bedc-84a0de00c35b", + Name: "sp1", + Namespace: "ns1", + }, + Spec: v1alpha1.SecurityPolicySpec{ + Rules: securityPolicyWithMultipleNormalPorts.Spec.Rules, + }, + } + + t.Run("build rule peer group name", func(t *testing.T) { + for _, tc := range []struct { + name string + ruleIdx int + isSource bool + enableVPC bool + expName string + expId string + }{ + { + name: "src rule without name", + ruleIdx: 0, + isSource: true, + enableVPC: true, + expName: "sp1-0-src", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_0_src", + }, + { + name: "dst rule without name", + ruleIdx: 0, + isSource: false, + enableVPC: true, + expName: "sp1-0-dst", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_0_dst", + }, + { + name: "dst rule without name with T1", + ruleIdx: 0, + isSource: false, + enableVPC: false, + expName: "sp1-0-dst", + expId: "sp_c5db1800-ce4c-11de-bedc-84a0de00c35b_0_dst", + }, + { + name: "src rule with name", + ruleIdx: 1, + isSource: true, + enableVPC: true, + expName: "MultipleNormalPorts-rule1-src", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_1_src", + }, + { + name: "dst rule with name", + ruleIdx: 1, + isSource: false, + enableVPC: true, + expName: "MultipleNormalPorts-rule1-dst", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_1_dst", + }, + { + name: "dst rule with name with T1", + ruleIdx: 1, + isSource: false, + enableVPC: false, + expName: "MultipleNormalPorts-rule1-dst", + expId: "sp_c5db1800-ce4c-11de-bedc-84a0de00c35b_1_dst", + }, + } { + t.Run(tc.name, func(t *testing.T) { + svc.NSXConfig.EnableVPCNetwork = tc.enableVPC + dispName := svc.buildRulePeerGroupName(obj, tc.ruleIdx, tc.isSource) + assert.Equal(t, tc.expName, dispName) + groupID := svc.buildRulePeerGroupID(obj, tc.ruleIdx, tc.isSource) + assert.Equal(t, tc.expId, groupID) + }) + } + + }) + + t.Run("build applied group name", func(t *testing.T) { + createdFor := common.ResourceTypeSecurityPolicy + for _, tc := range []struct { + name string + ruleIdx int + enableVPC bool + expName string + expId string + }{ + { + name: "rule without name", + ruleIdx: 0, + enableVPC: true, + expName: "sp1-0-scope", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_0_scope", + }, + { + name: "rule with name", + ruleIdx: 1, + enableVPC: true, + expName: "MultipleNormalPorts-rule1-scope", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_1_scope", + }, + { + name: "policy applied group", + ruleIdx: -1, + enableVPC: true, + expName: "ns1-sp1-scope", + expId: "sp1-c5db1800-ce4c-11de-bedc-84a0de00c35b_scope", + }, + { + name: "policy applied group with T1", + ruleIdx: -1, + enableVPC: false, + expName: "ns1-sp1-scope", + expId: "sp_c5db1800-ce4c-11de-bedc-84a0de00c35b_scope", + }, + } { + t.Run(tc.name, func(t *testing.T) { + svc.NSXConfig.EnableVPCNetwork = tc.enableVPC + dispName := svc.buildAppliedGroupName(obj, tc.ruleIdx) + assert.Equal(t, dispName, tc.expName) + id := svc.buildAppliedGroupID(obj, tc.ruleIdx, createdFor) + assert.Equal(t, tc.expId, id) + }) + } + }) +} diff --git a/pkg/nsx/services/securitypolicy/convert.go b/pkg/nsx/services/securitypolicy/convert.go new file mode 100644 index 000000000..fd6ba2d38 --- /dev/null +++ b/pkg/nsx/services/securitypolicy/convert.go @@ -0,0 +1,20 @@ +package securitypolicy + +import ( + "unsafe" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" + crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" +) + +func T1ToVPC(in *v1alpha1.SecurityPolicy) *crdv1alpha1.SecurityPolicy { + out := (*crdv1alpha1.SecurityPolicy)(unsafe.Pointer(in)) + out.APIVersion = "crd.nsx.vmware.com/v1alpha1" + return out +} + +func VPCToT1(in *crdv1alpha1.SecurityPolicy) *v1alpha1.SecurityPolicy { + out := (*v1alpha1.SecurityPolicy)(unsafe.Pointer(in)) + out.APIVersion = "nsx.vmware.com/v1alpha1" + return out +} diff --git a/pkg/nsx/services/securitypolicy/expand.go b/pkg/nsx/services/securitypolicy/expand.go index f6af9e159..3d802ff88 100644 --- a/pkg/nsx/services/securitypolicy/expand.go +++ b/pkg/nsx/services/securitypolicy/expand.go @@ -13,7 +13,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" "github.com/vmware-tanzu/nsx-operator/pkg/util" diff --git a/pkg/nsx/services/securitypolicy/expand_test.go b/pkg/nsx/services/securitypolicy/expand_test.go index e38cdd17b..782a4a636 100644 --- a/pkg/nsx/services/securitypolicy/expand_test.go +++ b/pkg/nsx/services/securitypolicy/expand_test.go @@ -15,7 +15,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" diff --git a/pkg/nsx/services/securitypolicy/firewall.go b/pkg/nsx/services/securitypolicy/firewall.go index f0d6c01de..50559d9f4 100644 --- a/pkg/nsx/services/securitypolicy/firewall.go +++ b/pkg/nsx/services/securitypolicy/firewall.go @@ -15,7 +15,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" @@ -23,7 +23,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log MarkedForDelete = true EnforceRevisionCheckParam = false ResourceTypeSecurityPolicy = common.ResourceTypeSecurityPolicy @@ -85,44 +85,7 @@ func InitializeSecurityPolicy(service common.Service, vpcService common.VPCServi } indexScope := common.TagValueScopeSecurityPolicyUID - securityPolicyService.securityPolicyStore = &SecurityPolicyStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer( - keyFunc, cache.Indexers{ - indexScope: indexBySecurityPolicyUID, - common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, - }), - BindingType: model.SecurityPolicyBindingType(), - }} - securityPolicyService.groupStore = &GroupStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ - indexScope: indexBySecurityPolicyUID, - common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, - common.TagScopeRuleID: indexGroupFunc, - }), - BindingType: model.GroupBindingType(), - }} - securityPolicyService.ruleStore = &RuleStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ - indexScope: indexBySecurityPolicyUID, - common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, - }), - BindingType: model.RuleBindingType(), - }} - - securityPolicyService.projectGroupStore = &GroupStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ - indexScope: indexBySecurityPolicyUID, - common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, - }), - BindingType: model.GroupBindingType(), - }} - securityPolicyService.shareStore = &ShareStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ - indexScope: indexBySecurityPolicyUID, - common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, - }), - BindingType: model.ShareBindingType(), - }} + securityPolicyService.setUpStore(indexScope) securityPolicyService.vpcService = vpcService projectGroupShareTag := []model.Tag{ @@ -164,6 +127,47 @@ func InitializeSecurityPolicy(service common.Service, vpcService common.VPCServi return securityPolicyService, nil } +func (s *SecurityPolicyService) setUpStore(indexScope string) { + s.securityPolicyStore = &SecurityPolicyStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer( + keyFunc, cache.Indexers{ + indexScope: indexBySecurityPolicyUID, + common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, + }), + BindingType: model.SecurityPolicyBindingType(), + }} + s.groupStore = &GroupStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ + indexScope: indexBySecurityPolicyUID, + common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, + common.TagScopeRuleID: indexGroupFunc, + }), + BindingType: model.GroupBindingType(), + }} + s.ruleStore = &RuleStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ + indexScope: indexBySecurityPolicyUID, + common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, + }), + BindingType: model.RuleBindingType(), + }} + + s.projectGroupStore = &GroupStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ + indexScope: indexBySecurityPolicyUID, + common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, + }), + BindingType: model.GroupBindingType(), + }} + s.shareStore = &ShareStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ + indexScope: indexBySecurityPolicyUID, + common.TagScopeNetworkPolicyUID: indexByNetworkPolicyUID, + }), + BindingType: model.ShareBindingType(), + }} +} + func (service *SecurityPolicyService) CreateOrUpdateSecurityPolicy(obj interface{}) error { if !nsxutil.IsLicensed(nsxutil.FeatureDFW) { log.Info("no DFW license, skip creating SecurityPolicy.") @@ -177,46 +181,122 @@ func (service *SecurityPolicyService) CreateOrUpdateSecurityPolicy(obj interface return err } for _, internalSecurityPolicy := range internalSecurityPolicies { - err = service.createOrUpdateSecurityPolicy(internalSecurityPolicy, common.ResourceTypeNetworkPolicy) + err = service.createOrUpdateVPCSecurityPolicy(internalSecurityPolicy, common.ResourceTypeNetworkPolicy) if err != nil { return err } } case *v1alpha1.SecurityPolicy: - err = service.createOrUpdateSecurityPolicy(obj.(*v1alpha1.SecurityPolicy), common.ResourceTypeSecurityPolicy) + if isVpcEnabled(service) { + err = service.createOrUpdateVPCSecurityPolicy(obj.(*v1alpha1.SecurityPolicy), common.ResourceTypeSecurityPolicy) + } else { + // For T1 network SecurityPolicy create/update + err = service.createOrUpdateSecurityPolicy(obj.(*v1alpha1.SecurityPolicy), common.ResourceTypeSecurityPolicy) + } } return err } -func (service *SecurityPolicyService) convertNetworkPolicyToInternalSecurityPolicies(networkPolicy *networkingv1.NetworkPolicy) ([]*v1alpha1.SecurityPolicy, error) { - securityPolicies := []*v1alpha1.SecurityPolicy{} +func (service *SecurityPolicyService) populateRulesForAllowSection(spAllow *v1alpha1.SecurityPolicy, networkPolicy *networkingv1.NetworkPolicy) error { actionAllow := v1alpha1.RuleActionAllow + directionIn := v1alpha1.RuleDirectionIn + directionOut := v1alpha1.RuleDirectionOut + for _, ingress := range networkPolicy.Spec.Ingress { + rule := &v1alpha1.SecurityPolicyRule{ + Action: &actionAllow, + Direction: &directionIn, + Sources: []v1alpha1.SecurityPolicyPeer{}, + } + for _, p := range ingress.From { + npPeer := p + spPeer, err := service.convertNetworkPolicyPeerToSecurityPolicyPeer(&npPeer) + if err != nil { + return err + } + rule.Sources = append(rule.Sources, *spPeer) + } + for _, p := range ingress.Ports { + npPort := p + spPort, err := service.convertNetworkPolicyPortToSecurityPolicyPort(&npPort) + if err != nil { + return err + } + rule.Ports = append(rule.Ports, *spPort) + } + spAllow.Spec.Rules = append(spAllow.Spec.Rules, *rule) + } + + for _, egress := range networkPolicy.Spec.Egress { + rule := &v1alpha1.SecurityPolicyRule{ + Action: &actionAllow, + Direction: &directionOut, + Destinations: []v1alpha1.SecurityPolicyPeer{}, + } + for _, p := range egress.To { + npPeer := p + spPeer, err := service.convertNetworkPolicyPeerToSecurityPolicyPeer(&npPeer) + if err != nil { + return err + } + rule.Destinations = append(rule.Destinations, *spPeer) + } + for _, p := range egress.Ports { + npPort := p + spPort, err := service.convertNetworkPolicyPortToSecurityPolicyPort(&npPort) + if err != nil { + return err + } + rule.Ports = append(rule.Ports, *spPort) + } + spAllow.Spec.Rules = append(spAllow.Spec.Rules, *rule) + } + return nil +} + +func (service *SecurityPolicyService) populateRulesForIsolationSection(spIsolation *v1alpha1.SecurityPolicy, networkPolicy *networkingv1.NetworkPolicy) error { actionDrop := v1alpha1.RuleActionDrop directionIn := v1alpha1.RuleDirectionIn directionOut := v1alpha1.RuleDirectionOut - spAllow := &v1alpha1.SecurityPolicy{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: networkPolicy.Namespace, - Name: service.BuildNetworkPolicyAllowPolicyName(networkPolicy.Name), - UID: types.UID(service.BuildNetworkPolicyAllowPolicyID(string(networkPolicy.UID))), - }, - Spec: v1alpha1.SecurityPolicySpec{ - Priority: common.PriorityNetworkPolicyAllowRule, - AppliedTo: []v1alpha1.SecurityPolicyTarget{ - { - PodSelector: &networkPolicy.Spec.PodSelector, - }, - }, - }, + for _, policyType := range networkPolicy.Spec.PolicyTypes { + if policyType == networkingv1.PolicyTypeIngress { + // Generating ingress deny rule in isolation section. + spIsolation.Spec.Rules = append(spIsolation.Spec.Rules, v1alpha1.SecurityPolicyRule{ + Action: &actionDrop, + Direction: &directionIn, + Name: "ingress-isolation", + }) + } else if policyType == networkingv1.PolicyTypeEgress { + // Generating egress deny rule in isolation section. + spIsolation.Spec.Rules = append(spIsolation.Spec.Rules, v1alpha1.SecurityPolicyRule{ + Action: &actionDrop, + Direction: &directionOut, + Name: "egress-isolation", + }) + } else { + // This logic branch is impossible, leave it just for following the coding rules. + return fmt.Errorf("invalid network policy type %s", policyType) + } } - spIsolation := &v1alpha1.SecurityPolicy{ + return nil +} + +func (service *SecurityPolicyService) generateSectionForNetworkPolicy(networkPolicy *networkingv1.NetworkPolicy, sectionType string) (*v1alpha1.SecurityPolicy, error) { + name := service.BuildNetworkPolicyAllowPolicyName(networkPolicy.Name) + uid := types.UID(service.BuildNetworkPolicyAllowPolicyID(string(networkPolicy.UID))) + priority := common.PriorityNetworkPolicyAllowRule + if sectionType == "isolation" { + name = service.BuildNetworkPolicyIsolationPolicyName(networkPolicy.Name) + uid = types.UID(service.BuildNetworkPolicyIsolationPolicyID(string(networkPolicy.UID))) + priority = common.PriorityNetworkPolicyIsolationRule + } + section := &v1alpha1.SecurityPolicy{ ObjectMeta: metav1.ObjectMeta{ Namespace: networkPolicy.Namespace, - Name: service.BuildNetworkPolicyIsolationPolicyName(networkPolicy.Name), - UID: types.UID(service.BuildNetworkPolicyIsolationPolicyID(string(networkPolicy.UID))), + Name: name, + UID: uid, }, Spec: v1alpha1.SecurityPolicySpec{ - Priority: common.PriorityNetworkPolicyIsolationRule, + Priority: priority, AppliedTo: []v1alpha1.SecurityPolicyTarget{ { PodSelector: &networkPolicy.Spec.PodSelector, @@ -224,72 +304,32 @@ func (service *SecurityPolicyService) convertNetworkPolicyToInternalSecurityPoli }, }, } + return section, nil +} - if len(networkPolicy.Spec.Ingress) > 0 { - spIsolation.Spec.Rules = []v1alpha1.SecurityPolicyRule{ - { - Action: &actionDrop, - Direction: &directionIn, - Name: "ingress-isolation", - }, - } - for _, ingress := range networkPolicy.Spec.Ingress { - rule := &v1alpha1.SecurityPolicyRule{ - Action: &actionAllow, - Direction: &directionIn, - Sources: []v1alpha1.SecurityPolicyPeer{}, - } - for _, p := range ingress.From { - npPeer := p - spPeer, err := service.convertNetworkPolicyPeerToSecurityPolicyPeer(&npPeer) - if err != nil { - return securityPolicies, err - } - rule.Sources = append(rule.Sources, *spPeer) - } - for _, p := range ingress.Ports { - npPort := p - spPort, err := service.convertNetworkPolicyPortToSecurityPolicyPort(&npPort) - if err != nil { - return securityPolicies, err - } - rule.Ports = append(rule.Ports, *spPort) - } - spAllow.Spec.Rules = append(spAllow.Spec.Rules, *rule) - } +func (service *SecurityPolicyService) convertNetworkPolicyToInternalSecurityPolicies(networkPolicy *networkingv1.NetworkPolicy) ([]*v1alpha1.SecurityPolicy, error) { + securityPolicies := []*v1alpha1.SecurityPolicy{} + + // Generating allow section. + spAllow, err := service.generateSectionForNetworkPolicy(networkPolicy, "allow") + if err != nil { + return nil, err + } + err = service.populateRulesForAllowSection(spAllow, networkPolicy) + if err != nil { + return nil, err } - if len(networkPolicy.Spec.Egress) > 0 { - spIsolation.Spec.Rules = append(spIsolation.Spec.Rules, v1alpha1.SecurityPolicyRule{ - Action: &actionDrop, - Direction: &directionOut, - Name: "egress-isolation", - }) - for _, egress := range networkPolicy.Spec.Egress { - rule := &v1alpha1.SecurityPolicyRule{ - Action: &actionAllow, - Direction: &directionOut, - Destinations: []v1alpha1.SecurityPolicyPeer{}, - } - for _, p := range egress.To { - npPeer := p - spPeer, err := service.convertNetworkPolicyPeerToSecurityPolicyPeer(&npPeer) - if err != nil { - return securityPolicies, err - } - rule.Destinations = append(rule.Destinations, *spPeer) - } - for _, p := range egress.Ports { - npPort := p - spPort, err := service.convertNetworkPolicyPortToSecurityPolicyPort(&npPort) - if err != nil { - return securityPolicies, err - } - rule.Ports = append(rule.Ports, *spPort) - } - spAllow.Spec.Rules = append(spAllow.Spec.Rules, *rule) - } + // Generating isolation section. + spIsolation, err := service.generateSectionForNetworkPolicy(networkPolicy, "isolation") + if err != nil { + return nil, err } + err = service.populateRulesForIsolationSection(spIsolation, networkPolicy) + if err != nil { + return nil, err + } + securityPolicies = append(securityPolicies, spAllow, spIsolation) log.V(1).Info("converted network policy to security policies", "securityPolicies", securityPolicies) return securityPolicies, nil @@ -349,12 +389,13 @@ func (service *SecurityPolicyService) getStores() (*SecurityPolicyStore, *RuleSt return service.securityPolicyStore, service.ruleStore, service.groupStore, service.projectGroupStore, service.shareStore } -func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1.SecurityPolicy, createdFor string) error { - securityPolicyStore, ruleStore, groupStore, projectGroupStore, shareStore := service.getStores() +func (service *SecurityPolicyService) getFinalSecurityPolicyResource(obj *v1alpha1.SecurityPolicy, createdFor string) (*model.SecurityPolicy, []model.Group, *[]ProjectShare, bool, error) { + securityPolicyStore, ruleStore, groupStore, _, _ := service.getStores() + nsxSecurityPolicy, nsxGroups, projectShares, err := service.buildSecurityPolicy(obj, createdFor) if err != nil { - log.Error(err, "failed to build SecurityPolicy") - return err + log.Error(err, "failed to build SecurityPolicy from CR", "ID", obj.UID) + return nil, nil, nil, false, err } if len(nsxSecurityPolicy.Scope) == 0 { @@ -364,25 +405,12 @@ func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1 if createdFor == common.ResourceTypeNetworkPolicy { indexScope = common.TagScopeNetworkPolicyUID } - existingSecurityPolicy := securityPolicyStore.GetByKey(*nsxSecurityPolicy.Id) - existingRules := ruleStore.GetByIndex(indexScope, string(obj.UID)) - existingGroups := groupStore.GetByIndex(indexScope, string(obj.UID)) + existingSecurityPolicy := securityPolicyStore.GetByKey(*nsxSecurityPolicy.Id) isChanged := true if existingSecurityPolicy != nil { isChanged = common.CompareResource(SecurityPolicyPtrToComparable(existingSecurityPolicy), SecurityPolicyPtrToComparable(nsxSecurityPolicy)) } - - changed, stale := common.CompareResources(RulesPtrToComparable(existingRules), RulesToComparable(nsxSecurityPolicy.Rules)) - changedRules, staleRules := ComparableToRules(changed), ComparableToRules(stale) - changed, stale = common.CompareResources(GroupsPtrToComparable(existingGroups), GroupsToComparable(*nsxGroups)) - changedGroups, staleGroups := ComparableToGroups(changed), ComparableToGroups(stale) - - if !isChanged && len(changedRules) == 0 && len(staleRules) == 0 && len(changedGroups) == 0 && len(staleGroups) == 0 { - log.Info("securityPolicy, rules and groups are not changed, skip updating them", "nsxSecurityPolicy.Id", nsxSecurityPolicy.Id) - return nil - } - var finalSecurityPolicy *model.SecurityPolicy if isChanged { finalSecurityPolicy = nsxSecurityPolicy @@ -390,120 +418,153 @@ func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1 finalSecurityPolicy = existingSecurityPolicy } - finalRules := make([]model.Rule, 0) - for i := len(staleRules) - 1; i >= 0; i-- { // Don't use range, it would copy the element - staleRules[i].MarkedForDelete = &MarkedForDelete // nsx clients need this field to delete the rules - } - finalRules = append(finalRules, staleRules...) - finalRules = append(finalRules, changedRules...) + existingRules := ruleStore.GetByIndex(indexScope, string(obj.UID)) + finalRules := service.updateRules(existingRules, nsxSecurityPolicy.Rules) finalSecurityPolicy.Rules = finalRules - finalGroups := make([]model.Group, 0) - for i := len(staleGroups) - 1; i >= 0; i-- { // Don't use range, it would copy the element - staleGroups[i].MarkedForDelete = &MarkedForDelete // nsx clients need this field to delete the group + existingGroups := groupStore.GetByIndex(indexScope, string(obj.UID)) + finalGroups := service.updateGroups(existingGroups, *nsxGroups) + + if isVpcEnabled(service) { + return finalSecurityPolicy, finalGroups, projectShares, isChanged, nil + } else { + return finalSecurityPolicy, finalGroups, nil, isChanged, nil + } +} + +func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1.SecurityPolicy, createdFor string) error { + finalSecurityPolicy, finalGroups, _, isChanged, err := service.getFinalSecurityPolicyResource(obj, createdFor) + if err != nil { + log.Error(err, "failed to get FinalSecurityPolicy from CR", "ID", obj.UID) + return err } - finalGroups = append(finalGroups, staleGroups...) - finalGroups = append(finalGroups, changedGroups...) // WrapHighLevelSecurityPolicy will modify the input security policy, so we need to make a copy for the following store update. finalSecurityPolicyCopy := *finalSecurityPolicy - finalSecurityPolicyCopy.Rules = finalRules - if isVpcEnabled(service) { - vpcInfo, err := service.getVpcInfo(obj.ObjectMeta.Namespace) + if !isChanged && len(finalSecurityPolicy.Rules) == 0 && len(finalGroups) == 0 { + log.Info("securityPolicy, rules, groups are not changed, skip updating them", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return nil + } + + infraSecurityPolicy, err := service.WrapHierarchySecurityPolicy(finalSecurityPolicy, finalGroups) + if err != nil { + log.Error(err, "failed to wrap SecurityPolicy", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return err + } + err = service.NSXClient.InfraClient.Patch(*infraSecurityPolicy, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) + if err != nil { + log.Error(err, "failed to create or update SecurityPolicy", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return err + } + // Get SecurityPolicy from NSX after HAPI call as NSX renders several fields like `path`/`parent_path`. + finalSecurityPolicyCopy, err = service.NSXClient.SecurityClient.Get(getDomain(service), *finalSecurityPolicy.Id) + err = nsxutil.NSXApiError(err) + if err != nil { + log.Error(err, "failed to get SecurityPolicy", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return err + } + + securityPolicyStore, ruleStore, groupStore, _, _ := service.getStores() + // The steps below know how to deal with NSX resources, if there is MarkedForDelete, then delete it from store, + // otherwise add or update it to store. + if isChanged { + err = securityPolicyStore.Apply(&finalSecurityPolicyCopy) if err != nil { + log.Error(err, "failed to apply store", "securityPolicy", finalSecurityPolicyCopy) return err } + } + err = ruleStore.Apply(&finalSecurityPolicyCopy) + if err != nil { + log.Error(err, "failed to apply store", "nsxRules", finalSecurityPolicyCopy.Rules) + return err + } + err = groupStore.Apply(&finalGroups) + if err != nil { + log.Error(err, "failed to apply store", "nsxGroups", finalGroups) + return err + } + log.Info("successfully created or updated NSX SecurityPolicy", "nsxSecurityPolicy", finalSecurityPolicyCopy) + return nil +} - finalProjectGroups := make([]model.Group, 0) - finalProjectShares := make([]model.Share, 0) - nsxProjectGroups := make([]model.Group, 0) - nsxProjectShares := make([]model.Share, 0) - for i := len(*projectShares) - 1; i >= 0; i-- { - nsxProjectGroups = append(nsxProjectGroups, *((*projectShares)[i].shareGroup)) - nsxProjectShares = append(nsxProjectShares, *((*projectShares)[i].share)) - } +func (service *SecurityPolicyService) createOrUpdateVPCSecurityPolicy(obj *v1alpha1.SecurityPolicy, createdFor string) error { + vpcInfo, err := service.getVpcInfo(obj.ObjectMeta.Namespace) + if err != nil { + return err + } - // Create/Update nsx project shares and nsx project level groups - existingNsxProjectGroups := projectGroupStore.GetByIndex(indexScope, string(obj.UID)) - changed, stale := common.CompareResources(GroupsPtrToComparable(existingNsxProjectGroups), GroupsToComparable(nsxProjectGroups)) - changedProjectGroups, staleProjectGroups := ComparableToGroups(changed), ComparableToGroups(stale) - if len(changedProjectGroups) == 0 && len(staleProjectGroups) == 0 { - log.Info("project groups are not changed, skip updating them") - } - for i := len(staleProjectGroups) - 1; i >= 0; i-- { - staleProjectGroups[i].MarkedForDelete = &MarkedForDelete - } - finalProjectGroups = append(finalProjectGroups, staleProjectGroups...) - finalProjectGroups = append(finalProjectGroups, changedProjectGroups...) - - existingNsxProjectShares := shareStore.GetByIndex(indexScope, string(obj.UID)) - changed, stale = common.CompareResources(SharesPtrToComparable(existingNsxProjectShares), SharesToComparable(nsxProjectShares)) - changedProjectShares, staleProjectShares := ComparableToShares(changed), ComparableToShares(stale) - if len(changedProjectShares) == 0 && len(staleProjectShares) == 0 { - log.Info("project shares are not changed, skip updating them") - } - for i := len(staleProjectShares) - 1; i >= 0; i-- { - staleProjectShares[i].MarkedForDelete = &MarkedForDelete - } - finalProjectShares = append(finalProjectShares, staleProjectShares...) - finalProjectShares = append(finalProjectShares, changedProjectShares...) + finalSecurityPolicy, finalGroups, projectShares, isChanged, err := service.getFinalSecurityPolicyResource(obj, createdFor) + if err != nil { + log.Error(err, "failed to get FinalSecurityPolicy from CR", "ID", obj.UID) + return err + } - // 1.Wrap project groups and shares into project child infra. - var projectInfra []*data.StructValue - if len(finalProjectGroups) != 0 || len(finalProjectShares) != 0 { - projectInfra, err = service.wrapHierarchyProjectResources(finalProjectShares, finalProjectGroups) - if err != nil { - log.Error(err, "failed to wrap project groups and shares") - return err - } - } + securityPolicyStore, ruleStore, groupStore, projectGroupStore, shareStore := service.getStores() + indexScope := common.TagValueScopeSecurityPolicyUID + if createdFor == common.ResourceTypeNetworkPolicy { + indexScope = common.TagScopeNetworkPolicyUID + } - // 2.Wrap SecurityPolicy, groups, rules under VPC level together with project groups and shares into one hierarchy resource tree. - orgRoot, err := service.WrapHierarchyVpcSecurityPolicy(finalSecurityPolicy, finalGroups, projectInfra, vpcInfo) - if err != nil { - log.Error(err, "failed to wrap SecurityPolicy in VPC") - return err - } + // WrapHierarchyVpcSecurityPolicy will modify the input security policy, so we need to make a copy for the following store update. + finalSecurityPolicyCopy := *finalSecurityPolicy - // 3.Create/update SecurityPolicy together with groups, rules under VPC level and project groups, shares. - err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) - if err != nil { - log.Error(err, "failed to create or update SecurityPolicy in VPC") - return err - } + nsxProjectGroups := make([]model.Group, 0) + nsxProjectShares := make([]model.Share, 0) + for i := len(*projectShares) - 1; i >= 0; i-- { + nsxProjectGroups = append(nsxProjectGroups, *((*projectShares)[i].shareGroup)) + nsxProjectShares = append(nsxProjectShares, *((*projectShares)[i].share)) + } - if len(finalProjectGroups) != 0 { - err = projectGroupStore.Apply(&finalProjectGroups) - if err != nil { - log.Error(err, "failed to apply store", "nsxProjectGroups", finalProjectGroups) - return err - } - } + // Create/Update nsx project shares and nsx project level groups + existingNsxProjectGroups := projectGroupStore.GetByIndex(indexScope, string(obj.UID)) + finalProjectGroups := service.updateGroups(existingNsxProjectGroups, nsxProjectGroups) - if len(finalProjectShares) != 0 { - err = shareStore.Apply(&finalProjectShares) - if err != nil { - log.Error(err, "failed to apply store", "nsxProjectShares", finalProjectShares) - return err - } - } - } else { - infraSecurityPolicy, err := service.WrapHierarchySecurityPolicy(finalSecurityPolicy, finalGroups) - if err != nil { - log.Error(err, "failed to wrap SecurityPolicy") - return err - } - err = service.NSXClient.InfraClient.Patch(*infraSecurityPolicy, &EnforceRevisionCheckParam) + existingNsxProjectShares := shareStore.GetByIndex(indexScope, string(obj.UID)) + finalProjectShares := service.updateShares(existingNsxProjectShares, nsxProjectShares) + + if !isChanged && len(finalSecurityPolicy.Rules) == 0 && len(finalGroups) == 0 && len(finalProjectGroups) == 0 && len(finalProjectShares) == 0 { + log.Info("securityPolicy, rules, groups and shares are not changed, skip updating them", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return nil + } + + // TODO: Simplify resource wrap and patch for both create/delete. + // 1.Wrap project groups and shares into project child infra. + var projectInfra []*data.StructValue + if len(finalProjectGroups) != 0 || len(finalProjectShares) != 0 { + projectInfra, err = service.wrapHierarchyProjectResources(finalProjectShares, finalProjectGroups) if err != nil { - log.Error(err, "failed to create or update SecurityPolicy") + log.Error(err, "failed to wrap project groups and shares", "nsxSecurityPolicyId", finalSecurityPolicy.Id) return err } } + + // 2.Wrap SecurityPolicy, groups, rules under VPC level together with project groups and shares into one hierarchy resource tree. + orgRoot, err := service.WrapHierarchyVpcSecurityPolicy(&finalSecurityPolicyCopy, finalGroups, projectInfra, vpcInfo) + if err != nil { + log.Error(err, "failed to wrap SecurityPolicy in VPC", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return err + } + + // 3.Create/update SecurityPolicy together with groups, rules under VPC level and project groups, shares. + err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) + if err != nil { + log.Error(err, "failed to create or update SecurityPolicy in VPC", "nsxSecurityPolicyId", finalSecurityPolicy.Id) + return err + } + + // Get SecurityPolicy from NSX after HAPI call as NSX renders several fields like `path`/`parent_path`. + finalSecurityPolicyCopy, err = service.NSXClient.VPCSecurityClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, *finalSecurityPolicyCopy.Id) + err = nsxutil.NSXApiError(err) if err != nil { + log.Error(err, "failed to get SecurityPolicy in VPC", "nsxSecurityPolicyId", finalSecurityPolicy.Id) return err } + // TODO: Simplify resource store update for both create/delete. // The steps below know how to deal with NSX resources, if there is MarkedForDelete, then delete it from store, // otherwise add or update it to store. if isChanged { @@ -513,227 +574,206 @@ func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1 return err } } - if !(len(changedRules) == 0 && len(staleRules) == 0) { - err = ruleStore.Apply(&finalSecurityPolicyCopy) - if err != nil { - log.Error(err, "failed to apply store", "nsxRules", finalSecurityPolicyCopy.Rules) - return err - } + + err = ruleStore.Apply(&finalSecurityPolicyCopy) + if err != nil { + log.Error(err, "failed to apply store", "nsxRules", finalSecurityPolicyCopy.Rules) + return err } - if !(len(changedGroups) == 0 && len(staleGroups) == 0) { - err = groupStore.Apply(&finalGroups) - if err != nil { - log.Error(err, "failed to apply store", "nsxGroups", finalGroups) - return err - } + err = groupStore.Apply(&finalGroups) + if err != nil { + log.Error(err, "failed to apply store", "nsxGroups", finalGroups) + return err + } + err = projectGroupStore.Apply(&finalProjectGroups) + if err != nil { + log.Error(err, "failed to apply store", "nsxProjectGroups", finalProjectGroups) + return err + } + err = shareStore.Apply(&finalProjectShares) + if err != nil { + log.Error(err, "failed to apply store", "nsxProjectShares", finalProjectShares) + return err } - log.Info("successfully created or updated nsx SecurityPolicy", "nsxSecurityPolicy", finalSecurityPolicyCopy) + + log.Info("successfully created or updated NSX SecurityPolicy in VPC", "nsxSecurityPolicy", finalSecurityPolicyCopy) return nil } func (service *SecurityPolicyService) DeleteSecurityPolicy(obj interface{}, isVpcCleanup bool, createdFor string) error { var err error - switch obj.(type) { + switch sp := obj.(type) { case *networkingv1.NetworkPolicy: - internalSecurityPolicies, err := service.convertNetworkPolicyToInternalSecurityPolicies(obj.(*networkingv1.NetworkPolicy)) - if err != nil { - return err + CRPolicySet := sets.New[string]() + CRPolicySet.Insert(service.BuildNetworkPolicyAllowPolicyID(string(sp.UID))) + CRPolicySet.Insert(service.BuildNetworkPolicyIsolationPolicyID(string(sp.UID))) + for elem := range CRPolicySet { + err = service.deleteVPCSecurityPolicy(types.UID(elem), createdFor) } - for _, internalSecurityPolicy := range internalSecurityPolicies { - err = service.deleteSecurityPolicy(internalSecurityPolicy, isVpcCleanup, createdFor) - if err != nil { - return err - } - } - case *v1alpha1.SecurityPolicy: - err = service.deleteSecurityPolicy(obj, isVpcCleanup, createdFor) case types.UID: - err = service.deleteSecurityPolicy(obj, isVpcCleanup, createdFor) + if isVpcEnabled(service) || isVpcCleanup { + err = service.deleteVPCSecurityPolicy(sp, createdFor) + } else { + // For T1 network SecurityPolicy deletion + err = service.deleteSecurityPolicy(sp) + } } return err } -func (service *SecurityPolicyService) deleteSecurityPolicy(obj interface{}, isVpcCleanup bool, createdFor string) error { +func (service *SecurityPolicyService) deleteSecurityPolicy(sp types.UID) error { var nsxSecurityPolicy *model.SecurityPolicy - var spNameSpace string var err error g := make([]model.Group, 0) nsxGroups := &g r := make([]model.Rule, 0) nsxRules := &r - var projectShares *[]ProjectShare - nsxProjectShares := make([]model.Share, 0) - nsxProjectGroups := make([]model.Group, 0) - securityPolicyStore, ruleStore, groupStore, projectGroupStore, shareStore := service.getStores() - switch sp := obj.(type) { - // This case is for normal SecurityPolicy deletion process, which means that SecurityPolicy - // has corresponding nsx SecurityPolicy object - case *v1alpha1.SecurityPolicy: - nsxSecurityPolicy, nsxGroups, projectShares, err = service.buildSecurityPolicy(sp, createdFor) - spNameSpace = sp.ObjectMeta.Namespace - if err != nil { - log.Error(err, "failed to build nsx SecurityPolicy in deleting") - return err - } + securityPolicyStore, ruleStore, groupStore, _, _ := service.getStores() - // Collect project share and project level groups that need to be removed from nsx - // project share and project groups only needed in VPC network. - for i := len(*projectShares) - 1; i >= 0; i-- { - nsxProjectGroups = append(nsxProjectGroups, *(*projectShares)[i].shareGroup) - nsxProjectShares = append(nsxProjectShares, *(*projectShares)[i].share) - } + // For normal SecurityPolicy deletion process, which means that SecurityPolicy has corresponding nsx SecurityPolicy object + // And for SecurityPolicy GC or cleanup process, which means that SecurityPolicy doesn't exist in K8s any more + // but still has corresponding nsx SecurityPolicy object. + // We use SecurityPolicy's UID from store to get NSX SecurityPolicy object + indexScope := common.TagValueScopeSecurityPolicyUID + existingSecurityPolices := securityPolicyStore.GetByIndex(indexScope, string(sp)) + if len(existingSecurityPolices) == 0 { + log.Info("NSX security policy is not found in store, skip deleting it", "nsxSecurityPolicyUID", sp) + return nil + } + nsxSecurityPolicy = existingSecurityPolices[0] + if nsxSecurityPolicy.Path == nil { + err = errors.New("nsxSecurityPolicy path is empty") + log.Error(err, "failed to delete SecurityPolicy", "nsxSecurityPolicyUID", sp) + return err + } - // This case is for SecurityPolicy GC or cleanup process, which means that SecurityPolicy - // doesn't exist in K8s any more but still has corresponding nsx SecurityPolicy object. - // Hence, we use SecurityPolicy's UID here from store instead of K8s SecurityPolicy object - case types.UID: - indexScope := common.TagValueScopeSecurityPolicyUID - if createdFor == common.ResourceTypeNetworkPolicy { - indexScope = common.TagScopeNetworkPolicyUID - } - existingSecurityPolices := securityPolicyStore.GetByIndex(indexScope, string(sp)) - if len(existingSecurityPolices) == 0 { - log.Info("NSX security policy is not found in store, skip deleting it", "nsxSecurityPolicyUID", sp, "createdFor", createdFor) - return nil - } - nsxSecurityPolicy = existingSecurityPolices[0] - // Get namespace of nsx SecurityPolicy from tags since there is no K8s SecurityPolicy object - for i := len(nsxSecurityPolicy.Tags) - 1; i >= 0; i-- { - if *(nsxSecurityPolicy.Tags[i].Scope) == common.TagScopeNamespace { - spNameSpace = *(nsxSecurityPolicy.Tags[i].Tag) - log.V(1).Info("get namespace with SecurityPolicy index", "namespace", spNameSpace, "securityPolicyUID", string(sp)) - break - } - } + nsxSecurityPolicy.MarkedForDelete = &MarkedForDelete - existingGroups := groupStore.GetByIndex(indexScope, string(sp)) - if len(existingGroups) == 0 { - log.Info("did not get groups with SecurityPolicy index", "securityPolicyUID", string(sp)) - } - for _, group := range existingGroups { - *nsxGroups = append(*nsxGroups, *group) - } + // There is no nsx groups/rules in the security policy retrieved from securityPolicy store. + // The groups/rules associated the deleting security policy can only be gotten from group/rule store. + existingGroups := groupStore.GetByIndex(indexScope, string(sp)) + service.markDeleteGroups(existingGroups, nsxGroups, sp) - // In GC or Cleanup process, there is no nsx rules in the security policy retrieved from securityPolicy store - // the rules associated the deleting security policy can only be gotten from rule store. - existingRules := ruleStore.GetByIndex(indexScope, string(sp)) - if len(existingRules) == 0 { - log.Info("did not get rules with SecurityPolicy index", "securityPolicyUID", string(sp)) - } - for _, rule := range existingRules { - *nsxRules = append(*nsxRules, *rule) - } - nsxSecurityPolicy.Rules = *nsxRules + existingRules := ruleStore.GetByIndex(indexScope, string(sp)) + service.markDeleteRules(existingRules, nsxRules, sp) + nsxSecurityPolicy.Rules = *nsxRules - if isVpcEnabled(service) || isVpcCleanup { - existingNsxProjectGroups := projectGroupStore.GetByIndex(indexScope, string(sp)) - if len(existingNsxProjectGroups) == 0 { - log.Info("did not get project groups with SecurityPolicy index", "securityPolicyUID", string(sp)) - } - for _, projectGroup := range existingNsxProjectGroups { - nsxProjectGroups = append(nsxProjectGroups, *projectGroup) - } - existingNsxProjectShares := shareStore.GetByIndex(indexScope, string(sp)) - if len(existingNsxProjectShares) == 0 { - log.Info("did not get project shares with SecurityPolicy index", "securityPolicyUID", string(sp)) - } - for _, nsxShare := range existingNsxProjectShares { - nsxProjectShares = append(nsxProjectShares, *nsxShare) - } - } + // WrapHighLevelSecurityPolicy will modify the input security policy, so we need to make a copy for the following store update. + finalSecurityPolicyCopy := *nsxSecurityPolicy + finalSecurityPolicyCopy.Rules = nsxSecurityPolicy.Rules + + infraSecurityPolicy, err := service.WrapHierarchySecurityPolicy(nsxSecurityPolicy, *nsxGroups) + if err != nil { + log.Error(err, "failed to wrap SecurityPolicy", "nsxSecurityPolicyId", nsxSecurityPolicy.Id) + return err + } + err = service.NSXClient.InfraClient.Patch(*infraSecurityPolicy, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) + if err != nil { + log.Error(err, "failed to delete SecurityPolicy", "nsxSecurityPolicyId", nsxSecurityPolicy.Id) + return err } - nsxSecurityPolicy.MarkedForDelete = &MarkedForDelete - for i := len(*nsxGroups) - 1; i >= 0; i-- { // Don't use range, it would copy the element - (*nsxGroups)[i].MarkedForDelete = &MarkedForDelete + err = securityPolicyStore.Apply(&finalSecurityPolicyCopy) + if err != nil { + log.Error(err, "failed to apply store", "securityPolicy", finalSecurityPolicyCopy) + return err } - for i := len(nsxSecurityPolicy.Rules) - 1; i >= 0; i-- { // Don't use range, it would copy the element - nsxSecurityPolicy.Rules[i].MarkedForDelete = &MarkedForDelete + err = ruleStore.Apply(&finalSecurityPolicyCopy) + if err != nil { + log.Error(err, "failed to apply store", "nsxRules", finalSecurityPolicyCopy.Rules) + return err + } + err = groupStore.Apply(nsxGroups) + if err != nil { + log.Error(err, "failed to apply store", "nsxGroups", nsxGroups) + return err } - // WrapHighLevelSecurityPolicy will modify the input security policy, so we need to make a copy for the following store update. - finalSecurityPolicyCopy := *nsxSecurityPolicy - finalSecurityPolicyCopy.Rules = nsxSecurityPolicy.Rules + log.Info("successfully deleted NSX SecurityPolicy", "nsxSecurityPolicy", finalSecurityPolicyCopy) + return nil +} - if isVpcEnabled(service) || isVpcCleanup { - var vpcInfo *common.VPCResourceInfo - if isVpcCleanup == false { - vpcInfo, err = service.getVpcInfo(spNameSpace) - if err != nil { - return err - } - } else { - // In cleanup process, vpcInfo should be listed directly from security policy store to avoid calling VPC service. - // Get orgId, projectId, vpcId from security policy path "/orgs//projects//vpcs//security-policies/" - if nsxSecurityPolicy.Path == nil { - err = errors.New("nsxSecurityPolicy path is empty") - log.Error(err, "failed to delete SecurityPolicy in VPC") - return err - } +func (service *SecurityPolicyService) deleteVPCSecurityPolicy(sp types.UID, createdFor string) error { + var nsxSecurityPolicy *model.SecurityPolicy + var err error + g := make([]model.Group, 0) + nsxGroups := &g + r := make([]model.Rule, 0) + nsxRules := &r + g1 := make([]model.Group, 0) + s := make([]model.Share, 0) + nsxProjectGroups := &g1 + nsxProjectShares := &s + securityPolicyStore, ruleStore, groupStore, projectGroupStore, shareStore := service.getStores() - vpcInfo = new(common.VPCResourceInfo) - vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, _ = nsxutil.ParseVPCPath(*(nsxSecurityPolicy.Path)) - } + // For normal SecurityPolicy deletion process, which means that SecurityPolicy has corresponding nsx SecurityPolicy object + // And for SecurityPolicy GC or cleanup process, which means that SecurityPolicy doesn't exist in K8s any more + // but still has corresponding nsx SecurityPolicy object. + // We use SecurityPolicy's UID from store to get NSX SecurityPolicy object + indexScope := common.TagValueScopeSecurityPolicyUID + if createdFor == common.ResourceTypeNetworkPolicy { + indexScope = common.TagScopeNetworkPolicyUID + } + existingSecurityPolices := securityPolicyStore.GetByIndex(indexScope, string(sp)) + if len(existingSecurityPolices) == 0 { + log.Info("NSX security policy is not found in store, skip deleting it", "nsxSecurityPolicyUID", sp, "createdFor", createdFor) + return nil + } + nsxSecurityPolicy = existingSecurityPolices[0] - for i := len(nsxProjectGroups) - 1; i >= 0; i-- { - nsxProjectGroups[i].MarkedForDelete = &MarkedForDelete - } - for i := len(nsxProjectShares) - 1; i >= 0; i-- { - nsxProjectShares[i].MarkedForDelete = &MarkedForDelete - } + // vpcInfo should be listed directly from security policy store to avoid calling VPC service. + // Get orgId, projectId, vpcId from security policy path "/orgs//projects//vpcs//security-policies/" + if nsxSecurityPolicy.Path == nil { + err = errors.New("nsxSecurityPolicy path is empty") + log.Error(err, "failed to delete SecurityPolicy in VPC", "nsxSecurityPolicyUID", sp) + return err + } + vpcInfo, _ := common.ParseVPCResourcePath(*(nsxSecurityPolicy.Path)) - // 1.Wrap project groups and shares into project child infra. - var projectInfra []*data.StructValue - if len(nsxProjectShares) != 0 || len(nsxProjectGroups) != 0 { - projectInfra, err = service.wrapHierarchyProjectResources(nsxProjectShares, nsxProjectGroups) - if err != nil { - log.Error(err, "failed to wrap project groups and shares") - return err - } - } + nsxSecurityPolicy.MarkedForDelete = &MarkedForDelete - // 2.Wrap SecurityPolicy, groups, rules under VPC level together with project groups and shares into one hierarchy resource tree. - orgRoot, err := service.WrapHierarchyVpcSecurityPolicy(nsxSecurityPolicy, *nsxGroups, projectInfra, vpcInfo) - if err != nil { - log.Error(err, "failed to wrap SecurityPolicy in VPC") - return err - } + // There is no nsx groups/rules in the security policy retrieved from securityPolicy store. + // The groups/rules associated the deleting security policy can only be gotten from group/rule store. + existingGroups := groupStore.GetByIndex(indexScope, string(sp)) + service.markDeleteGroups(existingGroups, nsxGroups, sp) - // 3.Create/update SecurityPolicy together with groups, rules under VPC level and project groups, shares. - err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) - if err != nil { - log.Error(err, "failed to delete SecurityPolicy in VPC") - return err - } + existingRules := ruleStore.GetByIndex(indexScope, string(sp)) + service.markDeleteRules(existingRules, nsxRules, sp) + nsxSecurityPolicy.Rules = *nsxRules - if len(nsxProjectGroups) != 0 { - err = projectGroupStore.Apply(&nsxProjectGroups) - if err != nil { - log.Error(err, "failed to apply store", "nsxProjectGroups", nsxProjectGroups) - return err - } - } + existingNsxProjectGroups := projectGroupStore.GetByIndex(indexScope, string(sp)) + service.markDeleteGroups(existingNsxProjectGroups, nsxProjectGroups, sp) - if len(nsxProjectShares) != 0 { - err = shareStore.Apply(&nsxProjectShares) - if err != nil { - log.Error(err, "failed to apply store", "nsxProjectShares", nsxProjectShares) - return err - } - } - } else { - infraSecurityPolicy, err := service.WrapHierarchySecurityPolicy(nsxSecurityPolicy, *nsxGroups) - if err != nil { - log.Error(err, "failed to wrap SecurityPolicy") - return err - } - err = service.NSXClient.InfraClient.Patch(*infraSecurityPolicy, &EnforceRevisionCheckParam) + existingNsxProjectShares := shareStore.GetByIndex(indexScope, string(sp)) + service.markDeleteShares(existingNsxProjectShares, nsxProjectShares, sp) + + // WrapHierarchyVpcSecurityPolicy will modify the input security policy, so we need to make a copy for the following store update. + finalSecurityPolicyCopy := *nsxSecurityPolicy + finalSecurityPolicyCopy.Rules = nsxSecurityPolicy.Rules + + // 1.Wrap project groups and shares into project child infra. + var projectInfra []*data.StructValue + if len(*nsxProjectShares) != 0 || len(*nsxProjectGroups) != 0 { + projectInfra, err = service.wrapHierarchyProjectResources(*nsxProjectShares, *nsxProjectGroups) if err != nil { - log.Error(err, "failed to delete SecurityPolicy") + log.Error(err, "failed to wrap project groups and shares", "nsxSecurityPolicyId", nsxSecurityPolicy.Id) return err } } + + // 2.Wrap SecurityPolicy, groups, rules under VPC level together with project groups and shares into one hierarchy resource tree. + orgRoot, err := service.WrapHierarchyVpcSecurityPolicy(nsxSecurityPolicy, *nsxGroups, projectInfra, &vpcInfo) + if err != nil { + log.Error(err, "failed to wrap SecurityPolicy in VPC", "nsxSecurityPolicyId", nsxSecurityPolicy.Id) + return err + } + + // 3.Create/update SecurityPolicy together with groups, rules under VPC level and project groups, shares. + err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) if err != nil { + log.Error(err, "failed to delete SecurityPolicy in VPC", "nsxSecurityPolicyId", nsxSecurityPolicy.Id) return err } @@ -752,8 +792,18 @@ func (service *SecurityPolicyService) deleteSecurityPolicy(obj interface{}, isVp log.Error(err, "failed to apply store", "nsxGroups", nsxGroups) return err } + err = projectGroupStore.Apply(nsxProjectGroups) + if err != nil { + log.Error(err, "failed to apply store", "nsxProjectGroups", nsxProjectGroups) + return err + } + err = shareStore.Apply(nsxProjectShares) + if err != nil { + log.Error(err, "failed to apply store", "nsxProjectShares", nsxProjectShares) + return err + } - log.Info("successfully deleted nsx SecurityPolicy", "nsxSecurityPolicy", finalSecurityPolicyCopy) + log.Info("successfully deleted NSX SecurityPolicy in VPC", "nsxSecurityPolicy", finalSecurityPolicyCopy) return nil } @@ -774,8 +824,10 @@ func (service *SecurityPolicyService) createOrUpdateGroups(obj *v1alpha1.Securit vpcId := (*vpcInfo).VPCID err = service.NSXClient.VpcGroupClient.Patch(orgId, projectId, vpcId, *group.Id, *group) + err = nsxutil.NSXApiError(err) } else { err = service.NSXClient.GroupClient.Patch(getDomain(service), *group.Id, *group) + err = nsxutil.NSXApiError(err) } } @@ -845,6 +897,81 @@ func (service *SecurityPolicyService) Cleanup(ctx context.Context) error { return nil } +func (service *SecurityPolicyService) updateRules(existingRules []*model.Rule, expectedRules []model.Rule) []model.Rule { + changed, stale := common.CompareResources(RulesPtrToComparable(existingRules), RulesToComparable(expectedRules)) + changedRules, staleRules := ComparableToRules(changed), ComparableToRules(stale) + finalRules := make([]model.Rule, 0) + for i := len(staleRules) - 1; i >= 0; i-- { // Don't use range, it would copy the element + staleRules[i].MarkedForDelete = &MarkedForDelete // nsx clients need this field to delete the rules + } + finalRules = append(finalRules, staleRules...) + finalRules = append(finalRules, changedRules...) + return finalRules +} + +func (service *SecurityPolicyService) updateGroups(existingGroups []*model.Group, expectedGroups []model.Group) []model.Group { + changed, stale := common.CompareResources(GroupsPtrToComparable(existingGroups), GroupsToComparable(expectedGroups)) + changedGroups, staleGroups := ComparableToGroups(changed), ComparableToGroups(stale) + finalGroups := make([]model.Group, 0) + for i := len(staleGroups) - 1; i >= 0; i-- { + staleGroups[i].MarkedForDelete = &MarkedForDelete + } + finalGroups = append(finalGroups, staleGroups...) + finalGroups = append(finalGroups, changedGroups...) + return finalGroups +} + +func (service *SecurityPolicyService) updateShares(existingShares []*model.Share, expectedShares []model.Share) []model.Share { + changed, stale := common.CompareResources(SharesPtrToComparable(existingShares), SharesToComparable(expectedShares)) + changedShares, staleShares := ComparableToShares(changed), ComparableToShares(stale) + for i := len(staleShares) - 1; i >= 0; i-- { + staleShares[i].MarkedForDelete = &MarkedForDelete + } + finalShares := make([]model.Share, 0) + finalShares = append(finalShares, staleShares...) + finalShares = append(finalShares, changedShares...) + return finalShares +} + +func (service *SecurityPolicyService) markDeleteGroups(existingGroups []*model.Group, deleteGroups *[]model.Group, sp types.UID) { + if len(existingGroups) == 0 { + log.Info("did not get groups with SecurityPolicy index", "securityPolicyUID", string(sp)) + return + } + for _, group := range existingGroups { + *deleteGroups = append(*deleteGroups, *group) + } + for i := len(*deleteGroups) - 1; i >= 0; i-- { + (*deleteGroups)[i].MarkedForDelete = &MarkedForDelete + } +} + +func (service *SecurityPolicyService) markDeleteRules(existingRules []*model.Rule, deleteRules *[]model.Rule, sp types.UID) { + if len(existingRules) == 0 { + log.Info("did not get rules with SecurityPolicy index", "securityPolicyUID", string(sp)) + return + } + for _, rule := range existingRules { + *deleteRules = append(*deleteRules, *rule) + } + for i := len(*deleteRules) - 1; i >= 0; i-- { + (*deleteRules)[i].MarkedForDelete = &MarkedForDelete + } +} + +func (service *SecurityPolicyService) markDeleteShares(existingShares []*model.Share, deleteShares *[]model.Share, sp types.UID) { + if len(existingShares) == 0 { + log.Info("did not get shares with SecurityPolicy index", "securityPolicyUID", string(sp)) + return + } + for _, share := range existingShares { + *deleteShares = append(*deleteShares, *share) + } + for i := len(*deleteShares) - 1; i >= 0; i-- { + (*deleteShares)[i].MarkedForDelete = &MarkedForDelete + } +} + func (s *SecurityPolicyService) getVpcInfo(spNameSpace string) (*common.VPCResourceInfo, error) { VPCInfo := s.vpcService.ListVPCInfo(spNameSpace) if len(VPCInfo) == 0 { diff --git a/pkg/nsx/services/securitypolicy/firewall_test.go b/pkg/nsx/services/securitypolicy/firewall_test.go index 3de499f59..d1a51a643 100644 --- a/pkg/nsx/services/securitypolicy/firewall_test.go +++ b/pkg/nsx/services/securitypolicy/firewall_test.go @@ -4,18 +4,22 @@ package securitypolicy import ( + "fmt" "reflect" "strings" "testing" + "github.com/agiledragon/gomonkey/v2" + "github.com/stretchr/testify/assert" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) @@ -367,3 +371,792 @@ func TestListSecurityPolicyID(t *testing.T) { }) } } + +func TestListUpdateRules(t *testing.T) { + r1 := model.Rule{ + DisplayName: String("nsxrule1"), + Id: String("nsxrule_1"), + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_scope"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_src"}, + Action: &nsxActionAllow, + } + + tests := []struct { + name string + existingRules []*model.Rule + expectedRules []model.Rule + finalRulesLen int + }{ + { + name: "test-rule-nochange", + existingRules: []*model.Rule{ + &r1, + }, + expectedRules: []model.Rule{ + { + DisplayName: String("nsxrule1"), + Id: String("nsxrule_1"), + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_scope"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_src"}, + Action: &nsxActionAllow, + }, + }, + finalRulesLen: 0, + }, + { + name: "test-rule-change", + existingRules: []*model.Rule{ + &r1, + }, + expectedRules: []model.Rule{ + { + DisplayName: String("nsxrule1"), + Id: String("nsxrule_1"), + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"/infra/domains/k8scl-one/groups/sp_uidA_1_scope"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_src"}, + Action: &nsxActionAllow, + }, + }, + finalRulesLen: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + finalRules := service.updateRules(tt.existingRules, tt.expectedRules) + assert.Equal(t, tt.finalRulesLen, len(finalRules)) + }) + } +} + +func TestListUpdateGroups(t *testing.T) { + mId, mTag, mTag2, mScope := "11111", "11111", "22222", "nsx-op/security_policy_cr_uid" + markDelete := true + + g1 := model.Group{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + MarkedForDelete: &markDelete, + } + + tests := []struct { + name string + existingGroups []*model.Group + expectedGroups []model.Group + finalGroupsLen int + }{ + { + name: "test-group-nochange", + existingGroups: []*model.Group{ + &g1, + }, + expectedGroups: []model.Group{ + { + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + MarkedForDelete: &markDelete, + }, + }, + finalGroupsLen: 0, + }, + { + name: "test-group-change", + existingGroups: []*model.Group{ + &g1, + }, + expectedGroups: []model.Group{ + { + Id: String("nsxgroup"), + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + MarkedForDelete: &markDelete, + }, + }, + finalGroupsLen: 2, + }, + { + name: "test-group-change1", + existingGroups: []*model.Group{ + &g1, + }, + expectedGroups: []model.Group{ + { + Id: &mId, + Tags: []model.Tag{{Tag: &mTag2, Scope: &mScope}}, + MarkedForDelete: &markDelete, + }, + }, + finalGroupsLen: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + finalGroups := service.updateGroups(tt.existingGroups, tt.expectedGroups) + assert.Equal(t, tt.finalGroupsLen, len(finalGroups)) + }) + } +} + +func TestListUpdateShares(t *testing.T) { + mId, mTag, mScope := "11111", "11111", "nsx-op/security_policy_cr_uid" + + s1 := model.Share{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + SharedWith: []string{"/org/default/project/default/vpc/vpc1"}, + } + + tests := []struct { + name string + existingShares []*model.Share + expectedShares []model.Share + finalSharesLen int + }{ + { + name: "test-share-nochange", + existingShares: []*model.Share{ + &s1, + }, + expectedShares: []model.Share{ + { + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + SharedWith: []string{"/org/default/project/default/vpc/vpc1"}, + }, + }, + finalSharesLen: 0, + }, + { + name: "test-share-change", + existingShares: []*model.Share{ + &s1, + }, + expectedShares: []model.Share{ + { + Id: String("nsxshare"), + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + SharedWith: []string{"/org/default/project/default/vpc/vpc1"}, + }, + }, + finalSharesLen: 2, + }, + { + name: "test-sahre-change1", + existingShares: []*model.Share{ + &s1, + }, + expectedShares: []model.Share{ + { + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + SharedWith: []string{"/org/default/project/default/vpc/vpc2"}, + }, + }, + finalSharesLen: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + finalShares := service.updateShares(tt.existingShares, tt.expectedShares) + assert.Equal(t, tt.finalSharesLen, len(finalShares)) + }) + } +} + +func TestListMarkDeleteRules(t *testing.T) { + var sp types.UID + sp = "sp_test" + markNoDelete := false + + r := make([]model.Rule, 0) + r1 := model.Rule{ + DisplayName: String("nsxrule1"), + Id: String("nsxrule_1"), + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_scope"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"/infra/domains/k8scl-one/groups/sp_uidA_0_src"}, + Action: &nsxActionAllow, + MarkedForDelete: &markNoDelete, + } + + tests := []struct { + name string + existingRules []*model.Rule + deleteRules *[]model.Rule + }{ + { + name: "test-rule-delete", + existingRules: []*model.Rule{ + &r1, + }, + deleteRules: &r, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + service.markDeleteRules(tt.existingRules, tt.deleteRules, sp) + for i := len(*tt.deleteRules) - 1; i >= 0; i-- { + assert.Equal(t, MarkedForDelete, *((*tt.deleteRules)[i].MarkedForDelete)) + } + }) + } +} + +func TestListMarkDeleteGroups(t *testing.T) { + var sp types.UID + sp = "sp_test" + mId, mTag, mScope := "11111", "11111", "nsx-op/security_policy_cr_uid" + markNoDelete := false + + g := make([]model.Group, 0) + g1 := model.Group{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + MarkedForDelete: &markNoDelete, + } + + tests := []struct { + name string + existingGroups []*model.Group + deleteGroups *[]model.Group + }{ + { + name: "test-group-delete", + existingGroups: []*model.Group{ + &g1, + }, + deleteGroups: &g, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + service.markDeleteGroups(tt.existingGroups, tt.deleteGroups, sp) + for i := len(*tt.deleteGroups) - 1; i >= 0; i-- { + assert.Equal(t, MarkedForDelete, *((*tt.deleteGroups)[i].MarkedForDelete)) + } + }) + } +} + +func TestListMarkDeleteShares(t *testing.T) { + var sp types.UID + sp = "sp_test" + mId, mTag, mScope := "11111", "11111", "nsx-op/security_policy_cr_uid" + markNoDelete := false + + s := make([]model.Share, 0) + s1 := model.Share{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + SharedWith: []string{"/org/default/project/default/vpc/vpc1"}, + MarkedForDelete: &markNoDelete, + } + + tests := []struct { + name string + existingShares []*model.Share + deleteShares *[]model.Share + }{ + { + name: "test-share-nochange", + existingShares: []*model.Share{ + &s1, + }, + deleteShares: &s, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + service.markDeleteShares(tt.existingShares, tt.deleteShares, sp) + for i := len(*tt.deleteShares) - 1; i >= 0; i-- { + assert.Equal(t, MarkedForDelete, *((*tt.deleteShares)[i].MarkedForDelete)) + } + }) + } +} + +func TestDleleteVPCSecurityPolicy(t *testing.T) { + vpcPath := "/orgs/default/projects/projectQuality/vpcs/vpc1" + + type args struct { + uid types.UID + createdFor string + } + tests := []struct { + name string + prepareFunc func(*testing.T, *SecurityPolicyService) *gomonkey.Patches + args args + inputPolicy *model.SecurityPolicy + wantErr bool + wantSecurityPolicyStoreCount int + wantRuleStoreCount int + wantGroupStoreCount int + wantProjectGroupStoreCount int + wantProjectShareStoreCount int + }{ + { + name: "successDeleteVPCSecurityPolicy", + prepareFunc: func(t *testing.T, s *SecurityPolicyService) *gomonkey.Patches { + mGId := "sp_uidA_0_scope" + mTag, mScope := tagValuePolicyCRUID, tagScopeSecurityPolicyCRUID + g := make([]model.Group, 0) + g1 := &g + scopeGroup := model.Group{ + Id: &mGId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + } + *g1 = append(*g1, scopeGroup) + assert.NoError(t, s.groupStore.Apply(g1)) + + mProjGId := "sp_uidA_1_src" + g = make([]model.Group, 0) + g2 := &g + projectGroup := model.Group{ + Id: &mProjGId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + } + *g2 = append(*g2, projectGroup) + assert.NoError(t, s.projectGroupStore.Apply(g2)) + + mSId := "share-projectQuality-group-sp_uidA_1_src" + sh := make([]model.Share, 0) + s1 := &sh + projectShare := model.Share{ + Id: &mSId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + SharedWith: []string{"/org/default/project/projectQuality/vpcs/vpc1"}, + } + *s1 = append(*s1, projectShare) + assert.NoError(t, s.shareStore.Apply(s1)) + + patches := gomonkey.ApplyMethodSeq(s.NSXClient.OrgRootClient, "Patch", []gomonkey.OutputCell{{ + Values: gomonkey.Params{nil}, + Times: 1, + }}) + return patches + }, + args: args{ + createdFor: common.ResourceTypeSecurityPolicy, + uid: types.UID(tagValuePolicyCRUID), + }, + inputPolicy: &model.SecurityPolicy{ + DisplayName: &spName, + Id: &tagValuePolicyCRUID, + Scope: []string{"/orgs/default/projects/projectQuality/vpcs/vpc1/groups/sp_uidA_scope"}, + SequenceNumber: &seq0, + Rules: []model.Rule{ + { + DisplayName: &ruleNameWithPodSelector00, + Id: &ruleID0, + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"ANY"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"ANY"}, + Action: &nsxActionAllow, + Tags: basicTags, + }, + { + DisplayName: &ruleNameWithNsSelector00, + Id: &ruleID1, + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"ANY"}, + SequenceNumber: &seq1, + Services: []string{"ANY"}, + SourceGroups: []string{"/orgs/default/projects/projectQuality/infra/domains/default/groups/sp_uidA_1_src"}, + Action: &nsxActionAllow, + Tags: basicTags, + }, + }, + Tags: basicTags, + Path: &vpcPath, + }, + wantErr: false, + wantSecurityPolicyStoreCount: 0, + wantRuleStoreCount: 0, + wantGroupStoreCount: 0, + wantProjectGroupStoreCount: 0, + wantProjectShareStoreCount: 0, + }, + { + name: "errorDeleteVPCSecurityPolicy", + prepareFunc: func(t *testing.T, s *SecurityPolicyService) *gomonkey.Patches { + mGId := "sp_uidA_0_scope" + mTag, mScope := tagValuePolicyCRUID, tagScopeSecurityPolicyCRUID + g := make([]model.Group, 0) + g1 := &g + scopeGroup := model.Group{ + Id: &mGId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + } + *g1 = append(*g1, scopeGroup) + assert.NoError(t, s.groupStore.Apply(g1)) + + patches := gomonkey.ApplyMethodSeq(s.NSXClient.OrgRootClient, "Patch", []gomonkey.OutputCell{{ + Values: gomonkey.Params{fmt.Errorf("mock error")}, + Times: 1, + }}) + return patches + }, + args: args{ + createdFor: common.ResourceTypeSecurityPolicy, + uid: types.UID(tagValuePolicyCRUID), + }, + inputPolicy: &model.SecurityPolicy{ + DisplayName: &spName, + Id: &tagValuePolicyCRUID, + Scope: []string{"/orgs/default/projects/default/vpcs/vpc1/groups/sp_uidA_scope"}, + SequenceNumber: &seq0, + Rules: []model.Rule{ + { + DisplayName: &ruleNameWithPodSelector00, + Id: &ruleID0, + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"ANY"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"ANY"}, + Action: &nsxActionAllow, + Tags: basicTags, + }, + }, + Tags: basicTags, + Path: &vpcPath, + }, + wantErr: true, + wantSecurityPolicyStoreCount: 1, + wantRuleStoreCount: 1, + wantGroupStoreCount: 1, + wantProjectGroupStoreCount: 0, + wantProjectShareStoreCount: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeService := fakeSecurityPolicyService() + fakeService.setUpStore(common.TagValueScopeSecurityPolicyUID) + + assert.NoError(t, fakeService.securityPolicyStore.Apply(tt.inputPolicy)) + assert.NoError(t, fakeService.ruleStore.Apply(tt.inputPolicy)) + + patches := tt.prepareFunc(t, fakeService) + defer patches.Reset() + + if err := fakeService.deleteVPCSecurityPolicy(tt.args.uid, tt.args.createdFor); (err != nil) != tt.wantErr { + t.Errorf("deleteVPCSecurityPolicy error = %v, wantErr %v", err, tt.wantErr) + } + assert.Equal(t, tt.wantSecurityPolicyStoreCount, len(fakeService.securityPolicyStore.ListKeys())) + assert.Equal(t, tt.wantRuleStoreCount, len(fakeService.ruleStore.ListKeys())) + assert.Equal(t, tt.wantGroupStoreCount, len(fakeService.groupStore.ListKeys())) + assert.Equal(t, tt.wantProjectGroupStoreCount, len(fakeService.projectGroupStore.ListKeys())) + assert.Equal(t, tt.wantProjectShareStoreCount, len(fakeService.shareStore.ListKeys())) + }) + } +} + +func TestCreateOrUpdateSecurityPolicy(t *testing.T) { + VPCInfo := make([]common.VPCResourceInfo, 1) + VPCInfo[0].OrgID = "default" + VPCInfo[0].ProjectID = "projectQuality" + VPCInfo[0].VPCID = "vpc1" + + fakeService := fakeSecurityPolicyService() + fakeService.NSXConfig.EnableVPCNetwork = true + mockVPCService := common.MockVPCServiceProvider{} + fakeService.vpcService = &mockVPCService + + podSelectorRule0IDPort000 := fakeService.buildExpandedRuleId(fakeService.buildRuleID(&spWithPodSelector, &spWithPodSelector.Spec.Rules[0], 0, common.ResourceTypeSecurityPolicy), 0, 0) + podSelectorRule1IDPort000 := fakeService.buildExpandedRuleId(fakeService.buildRuleID(&spWithPodSelector, &spWithPodSelector.Spec.Rules[1], 1, common.ResourceTypeSecurityPolicy), 0, 0) + + podSelectorRule0Name00, _ := fakeService.buildRuleDisplayName(&spWithPodSelector.Spec.Rules[0], 0, -1, false, common.ResourceTypeSecurityPolicy) + podSelectorRule1Name00, _ := fakeService.buildRuleDisplayName(&spWithPodSelector.Spec.Rules[1], 0, -1, false, common.ResourceTypeSecurityPolicy) + + type args struct { + spObj *v1alpha1.SecurityPolicy + createdFor string + } + tests := []struct { + name string + prepareFunc func(*testing.T, *SecurityPolicyService) *gomonkey.Patches + args args + expectedPolicy *model.SecurityPolicy + wantErr bool + wantSecurityPolicyStoreCount int + wantRuleStoreCount int + wantGroupStoreCount int + wantProjectGroupStoreCount int + wantProjectShareStoreCount int + }{ + { + name: "successCreateUpdateVPCSecurityPolicy", + prepareFunc: func(t *testing.T, s *SecurityPolicyService) *gomonkey.Patches { + patches := gomonkey.ApplyPrivateMethod(reflect.TypeOf(s), "getVpcInfo", + func(s *SecurityPolicyService, spNameSpace string) (*common.VPCResourceInfo, error) { + return &VPCInfo[0], nil + }) + + patches.ApplyMethodSeq(s.NSXClient.OrgRootClient, "Patch", []gomonkey.OutputCell{{ + Values: gomonkey.Params{nil}, + Times: 1, + }}) + + patches.ApplyPrivateMethod(reflect.TypeOf(s), "getNamespaceUID", + func(s *SecurityPolicyService, ns string) types.UID { + return types.UID(tagValueNSUID) + }) + + return patches + }, + args: args{ + createdFor: common.ResourceTypeSecurityPolicy, + spObj: &spWithPodSelector, + }, + expectedPolicy: &model.SecurityPolicy{ + DisplayName: &spName, + Id: &spID, + Scope: []string{"/orgs/default/projects/projectQuality/vpcs/vpc1/groups/sp_uidA_scope"}, + SequenceNumber: &seq0, + Rules: []model.Rule{ + { + DisplayName: &podSelectorRule0Name00, + Id: &podSelectorRule0IDPort000, + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"/orgs/default/projects/projectQuality/vpcs/vpc1/groups/sp_uidA_0_scope"}, + SequenceNumber: &seq0, + Services: []string{"ANY"}, + SourceGroups: []string{"/orgs/default/projects/projectQuality/infra/domains/default/groups/sp_uidA_0_src"}, + Action: &nsxActionAllow, + Tags: basicTags, + }, + { + DisplayName: &podSelectorRule1Name00, + Id: &podSelectorRule1IDPort000, + DestinationGroups: []string{"ANY"}, + Direction: &nsxDirectionIn, + Scope: []string{"ANY"}, + SequenceNumber: &seq1, + Services: []string{"ANY"}, + SourceGroups: []string{"/orgs/default/projects/projectQuality/infra/domains/default/groups/sp_uidA_1_src"}, + Action: &nsxActionAllow, + Tags: basicTags, + }, + }, + Tags: basicTags, + }, + wantErr: false, + wantSecurityPolicyStoreCount: 1, + wantRuleStoreCount: 2, + wantGroupStoreCount: 2, + wantProjectGroupStoreCount: 2, + wantProjectShareStoreCount: 2, + }, + { + name: "errorCreateUpdateVPCSecurityPolicy", + prepareFunc: func(t *testing.T, s *SecurityPolicyService) *gomonkey.Patches { + patches := gomonkey.ApplyPrivateMethod(reflect.TypeOf(s), "getVpcInfo", + func(s *SecurityPolicyService, spNameSpace string) (*common.VPCResourceInfo, error) { + return &VPCInfo[0], nil + }) + + patches.ApplyMethodSeq(s.NSXClient.OrgRootClient, "Patch", []gomonkey.OutputCell{{ + Values: gomonkey.Params{fmt.Errorf("mock error")}, + Times: 1, + }}) + + patches.ApplyPrivateMethod(reflect.TypeOf(s), "getNamespaceUID", + func(s *SecurityPolicyService, ns string) types.UID { + return types.UID(tagValueNSUID) + }) + + return patches + }, + args: args{ + createdFor: common.ResourceTypeSecurityPolicy, + spObj: &spWithPodSelector, + }, + expectedPolicy: &model.SecurityPolicy{}, + wantErr: true, + wantSecurityPolicyStoreCount: 0, + wantRuleStoreCount: 0, + wantGroupStoreCount: 0, + wantProjectGroupStoreCount: 0, + wantProjectShareStoreCount: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeService.setUpStore(common.TagValueScopeSecurityPolicyUID) + + patches := tt.prepareFunc(t, fakeService) + patches.ApplyMethodSeq(fakeService.NSXClient.VPCSecurityClient, "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{*(tt.expectedPolicy), nil}, + Times: 1, + }}) + defer patches.Reset() + + if err := fakeService.createOrUpdateVPCSecurityPolicy(tt.args.spObj, tt.args.createdFor); (err != nil) != tt.wantErr { + t.Errorf("createOrUpdateVPCSecurityPolicy error = %v, wantErr %v", err, tt.wantErr) + } + + assert.Equal(t, tt.wantSecurityPolicyStoreCount, len(fakeService.securityPolicyStore.ListKeys())) + assert.Equal(t, tt.wantRuleStoreCount, len(fakeService.ruleStore.ListKeys())) + assert.Equal(t, tt.wantGroupStoreCount, len(fakeService.groupStore.ListKeys())) + assert.Equal(t, tt.wantProjectGroupStoreCount, len(fakeService.projectGroupStore.ListKeys())) + assert.Equal(t, tt.wantProjectShareStoreCount, len(fakeService.shareStore.ListKeys())) + }) + } +} + +func TestGetFinalSecurityPolicyResouce(t *testing.T) { + VPCInfo := make([]common.VPCResourceInfo, 1) + VPCInfo[0].OrgID = "default" + VPCInfo[0].ProjectID = "projectQuality" + VPCInfo[0].VPCID = "vpc1" + + fakeService := fakeSecurityPolicyService() + mockVPCService := common.MockVPCServiceProvider{} + fakeService.vpcService = &mockVPCService + + type args struct { + spObj *v1alpha1.SecurityPolicy + createdFor string + } + tests := []struct { + name string + prepareFunc func(*testing.T, *SecurityPolicyService) *gomonkey.Patches + args args + expectedPolicy *model.SecurityPolicy + wantErr bool + wantSecurityPolicyChanged bool + wantRuleStoreCount int + wantGroupStoreCount int + wantProjectGroupStoreCount int + }{ + { + name: "getFinalSecurityPolicyResouceForVPCMode", + prepareFunc: func(t *testing.T, s *SecurityPolicyService) *gomonkey.Patches { + s.NSXConfig.EnableVPCNetwork = true + + patches := gomonkey.ApplyPrivateMethod(reflect.TypeOf(s), "getVpcInfo", + func(s *SecurityPolicyService, spNameSpace string) (*common.VPCResourceInfo, error) { + return &VPCInfo[0], nil + }) + + patches.ApplyPrivateMethod(reflect.TypeOf(s), "getNamespaceUID", + func(s *SecurityPolicyService, ns string) types.UID { + return types.UID(tagValueNSUID) + }) + + return patches + }, + args: args{ + createdFor: common.ResourceTypeSecurityPolicy, + spObj: &spWithPodSelector, + }, + expectedPolicy: &model.SecurityPolicy{ + DisplayName: common.String("spA"), + Id: common.String("spA-uidA"), + Scope: []string{"/orgs/default/projects/projectQuality/vpcs/vpc1/groups/spA-uidA_scope"}, + SequenceNumber: &seq0, + Rules: []model.Rule{}, + Tags: basicTags, + }, + wantErr: false, + wantSecurityPolicyChanged: true, + wantRuleStoreCount: 2, + wantGroupStoreCount: 2, + wantProjectGroupStoreCount: 2, + }, + { + name: "getFinalSecurityPolicyResouceForT1", + prepareFunc: func(t *testing.T, s *SecurityPolicyService) *gomonkey.Patches { + s.NSXConfig.EnableVPCNetwork = false + + patches := gomonkey.ApplyPrivateMethod(reflect.TypeOf(s), "getVpcInfo", + func(s *SecurityPolicyService, spNameSpace string) (*common.VPCResourceInfo, error) { + return &VPCInfo[0], nil + }) + + patches.ApplyPrivateMethod(reflect.TypeOf(s), "getNamespaceUID", + func(s *SecurityPolicyService, ns string) types.UID { + return types.UID(tagValueNSUID) + }) + + return patches + }, + args: args{ + createdFor: common.ResourceTypeSecurityPolicy, + spObj: &spWithPodSelector, + }, + expectedPolicy: &model.SecurityPolicy{ + DisplayName: &spName, + Id: &spID, + Scope: []string{"/infra/domains/k8scl-one:test/groups/sp_uidA_scope"}, + SequenceNumber: &seq0, + Rules: []model.Rule{}, + Tags: basicTags, + }, + wantErr: false, + wantSecurityPolicyChanged: true, + wantRuleStoreCount: 2, + wantGroupStoreCount: 4, + wantProjectGroupStoreCount: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeService.setUpStore(common.TagValueScopeSecurityPolicyUID) + + patches := tt.prepareFunc(t, fakeService) + defer patches.Reset() + + var finalSecurityPolicy *model.SecurityPolicy + var finalGroups []model.Group + var projectShares *[]ProjectShare + var isChanged bool + var err error + + if finalSecurityPolicy, finalGroups, projectShares, isChanged, err = fakeService.getFinalSecurityPolicyResource(tt.args.spObj, tt.args.createdFor); (err != nil) != tt.wantErr { + t.Errorf("getFinalSecurityPolicyResouce error = %v, wantErr %v", err, tt.wantErr) + } + + assert.Equal(t, *tt.expectedPolicy.Id, *finalSecurityPolicy.Id) + assert.Equal(t, tt.expectedPolicy.Scope[0], finalSecurityPolicy.Scope[0]) + assert.Equal(t, true, isChanged) + assert.Equal(t, tt.wantGroupStoreCount, len(finalGroups)) + assert.Equal(t, tt.wantRuleStoreCount, len(finalSecurityPolicy.Rules)) + + if fakeService.NSXConfig.EnableVPCNetwork { + assert.Equal(t, tt.wantProjectGroupStoreCount, len(*projectShares)) + } else { + assert.Equal(t, (*[]ProjectShare)(nil), projectShares) + } + }) + } +} diff --git a/pkg/nsx/services/securitypolicy/parse.go b/pkg/nsx/services/securitypolicy/parse.go index a43cb80aa..1ba794296 100644 --- a/pkg/nsx/services/securitypolicy/parse.go +++ b/pkg/nsx/services/securitypolicy/parse.go @@ -3,7 +3,7 @@ package securitypolicy import ( "errors" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) diff --git a/pkg/nsx/services/securitypolicy/wrap_test.go b/pkg/nsx/services/securitypolicy/wrap_test.go index da1b3da9c..86f4b54d8 100644 --- a/pkg/nsx/services/securitypolicy/wrap_test.go +++ b/pkg/nsx/services/securitypolicy/wrap_test.go @@ -14,7 +14,13 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) -type fakeQueryClient struct{} +type ( + fakeQueryClient struct{} + fakeInfraClient struct{} + fakeOrgClient struct{} + fakeSecurityClient struct{} + fakeVPCSecurityClient struct{} +) func (_ *fakeQueryClient) List(_ string, _ *string, _ *string, _ *int64, _ *bool, _ *string) (model.SearchResponse, error) { cursor := "2" @@ -25,15 +31,95 @@ func (_ *fakeQueryClient) List(_ string, _ *string, _ *string, _ *int64, _ *bool }, nil } -func fakeService() *SecurityPolicyService { +func (f fakeInfraClient) Get(basePathParam *string, filterParam *string, typeFilterParam *string) (model.Infra, error) { + return model.Infra{}, nil +} + +func (f fakeInfraClient) Update(infraParam model.Infra) (model.Infra, error) { + return model.Infra{}, nil +} + +func (f fakeInfraClient) Patch(infraParam model.Infra, enforceRevisionCheckParam *bool) error { + return nil +} + +func (f fakeSecurityClient) Delete(domainIdParam string, securityPolicyIdParam string) error { + return nil +} + +func (f fakeSecurityClient) Get(domainIdParam string, securityPolicyIdParam string) (model.SecurityPolicy, error) { + return model.SecurityPolicy{}, nil +} + +func (f fakeSecurityClient) List(domainIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includeRuleCountParam *bool, includedFieldsParam *string, + pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string, +) (model.SecurityPolicyListResult, error) { + return model.SecurityPolicyListResult{}, nil +} + +func (f fakeSecurityClient) Patch(domainIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy) error { + return nil +} + +func (f fakeSecurityClient) Revise(domainIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy, + anchorPathParam *string, operationParam *string, +) (model.SecurityPolicy, error) { + return model.SecurityPolicy{}, nil +} + +func (f fakeSecurityClient) Update(domainIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy) (model.SecurityPolicy, error) { + return model.SecurityPolicy{}, nil +} + +func (f fakeOrgClient) Get(basePathParam *string, filterParam *string, typeFilterParam *string) (model.OrgRoot, error) { + return model.OrgRoot{}, nil +} + +func (f fakeOrgClient) Patch(orgRootParam model.OrgRoot, enforceRevisionCheckParam *bool) error { + return nil +} + +func (f fakeVPCSecurityClient) Delete(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string) error { + return nil +} + +func (f fakeVPCSecurityClient) Get(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string) (model.SecurityPolicy, error) { + return model.SecurityPolicy{}, nil +} + +func (f fakeVPCSecurityClient) List(orgIdParam string, projectIdParam string, vpcIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, + includeRuleCountParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string, +) (model.SecurityPolicyListResult, error) { + return model.SecurityPolicyListResult{}, nil +} + +func (f fakeVPCSecurityClient) Patch(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy) error { + return nil +} + +func (f fakeVPCSecurityClient) Revise(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy, + anchorPathParam *string, operationParam *string, +) (model.SecurityPolicy, error) { + return model.SecurityPolicy{}, nil +} + +func (f fakeVPCSecurityClient) Update(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy) (model.SecurityPolicy, error) { + return model.SecurityPolicy{}, nil +} + +func fakeSecurityPolicyService() *SecurityPolicyService { c := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) cluster, _ := nsx.NewCluster(c) rc, _ := cluster.NewRestConnector() - service = &SecurityPolicyService{ + fakeService := &SecurityPolicyService{ Service: common.Service{ NSXClient: &nsx.Client{ - QueryClient: &fakeQueryClient{}, - RestConnector: rc, + QueryClient: &fakeQueryClient{}, + InfraClient: &fakeInfraClient{}, + SecurityClient: &fakeSecurityClient{}, + OrgRootClient: &fakeOrgClient{}, + VPCSecurityClient: &fakeVPCSecurityClient{}, + RestConnector: rc, NsxConfig: &config.NSXOperatorConfig{ CoeConfig: &config.CoeConfig{ Cluster: "k8scl-one:test", @@ -47,12 +133,12 @@ func fakeService() *SecurityPolicyService { }, }, } - return service + return fakeService } func TestSecurityPolicyService_wrapSecurityPolicy(t *testing.T) { Converter := bindings.NewTypeConverter() - service := fakeService() + service := fakeSecurityPolicyService() mId, mTag, mScope := "11111", "11111", "nsx-op/security_policy_cr_uid" markDelete := true s := model.SecurityPolicy{ @@ -87,7 +173,7 @@ func TestSecurityPolicyService_wrapSecurityPolicy(t *testing.T) { func TestSecurityPolicyService_wrapGroups(t *testing.T) { Converter := bindings.NewTypeConverter() - service := fakeService() + service := fakeSecurityPolicyService() mId, mTag, mScope := "11111", "11111", "nsx-op/security_policy_cr_uid" markDelete := true m := model.Group{ @@ -123,7 +209,7 @@ func TestSecurityPolicyService_wrapGroups(t *testing.T) { func TestSecurityPolicyService_wrapRules(t *testing.T) { Converter := bindings.NewTypeConverter() - service := fakeService() + service := fakeSecurityPolicyService() mId, mTag, mScope := "11111", "11111", "nsx-op/security_policy_cr_uid" markDelete := true r := model.Rule{ @@ -159,7 +245,7 @@ func TestSecurityPolicyService_wrapRules(t *testing.T) { func TestSecurityPolicyService_wrapResourceReference(t *testing.T) { Converter := bindings.NewTypeConverter() - service := fakeService() + service := fakeSecurityPolicyService() type args struct { children []*data.StructValue } diff --git a/pkg/nsx/services/staticroute/builder.go b/pkg/nsx/services/staticroute/builder.go index 457e29bc3..d2d88871a 100644 --- a/pkg/nsx/services/staticroute/builder.go +++ b/pkg/nsx/services/staticroute/builder.go @@ -6,7 +6,7 @@ import ( "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) @@ -42,8 +42,8 @@ func (service *StaticRouteService) buildStaticRoute(obj *v1alpha1.StaticRoute) ( nexthop.IpAddress = &obj.Spec.NextHops[index].IPAddress sr.NextHops = append(sr.NextHops, nexthop) } - sr.Id = String(util.GenerateID(string(obj.UID), "sr", "", "")) - sr.DisplayName = String(util.GenerateTruncName(common.MaxNameLength, obj.Name, "sr", "", "", "")) + sr.Id = String(util.GenerateIDByObject(obj)) + sr.DisplayName = String(util.GenerateTruncName(common.MaxNameLength, obj.Name, "", "", "", "")) sr.Tags = service.buildBasicTags(obj) return sr, nil } diff --git a/pkg/nsx/services/staticroute/builder_test.go b/pkg/nsx/services/staticroute/builder_test.go index cec16321c..d0e7967d1 100644 --- a/pkg/nsx/services/staticroute/builder_test.go +++ b/pkg/nsx/services/staticroute/builder_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" ) @@ -33,6 +33,7 @@ func TestBuildStaticRoute(t *testing.T) { obj.Spec.NextHops = []v1alpha1.NextHop{{IPAddress: ip1}, {IPAddress: ip2}} obj.ObjectMeta.Name = "teststaticroute" obj.ObjectMeta.Namespace = "qe" + obj.ObjectMeta.UID = "uuid1" service := &StaticRouteService{} service.NSXConfig = &config.NSXOperatorConfig{} service.NSXConfig.CoeConfig = &config.CoeConfig{} @@ -40,4 +41,8 @@ func TestBuildStaticRoute(t *testing.T) { staticroutes, err := service.buildStaticRoute(obj) assert.Equal(t, err, nil) assert.Equal(t, len(staticroutes.NextHops), 2) + expName := "teststaticroute" + assert.Equal(t, expName, *staticroutes.DisplayName) + expId := "teststaticroute-uuid1" + assert.Equal(t, expId, *staticroutes.Id) } diff --git a/pkg/nsx/services/staticroute/staticroute.go b/pkg/nsx/services/staticroute/staticroute.go index 9eec6b218..87d7c16da 100644 --- a/pkg/nsx/services/staticroute/staticroute.go +++ b/pkg/nsx/services/staticroute/staticroute.go @@ -10,10 +10,11 @@ import ( "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "k8s.io/client-go/tools/cache" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" + "github.com/vmware-tanzu/nsx-operator/pkg/util" ) type StaticRouteService struct { @@ -23,7 +24,7 @@ type StaticRouteService struct { } var ( - log = logger.Log + log = &logger.Log resourceTypeStaticRoute = "StaticRoutes" String = common.String ) @@ -83,6 +84,7 @@ func (service *StaticRouteService) CreateOrUpdateStaticRoute(namespace string, o return err } staticRoute, err := service.NSXClient.StaticRouteClient.Get(vpc[0].OrgID, vpc[0].ProjectID, vpc[0].ID, *nsxStaticRoute.Id) + err = nsxutil.NSXApiError(err) if err != nil { return err } @@ -95,20 +97,22 @@ func (service *StaticRouteService) CreateOrUpdateStaticRoute(namespace string, o func (service *StaticRouteService) patch(orgId string, projectId string, vpcId string, st *model.StaticRoutes) error { err := service.NSXClient.StaticRouteClient.Patch(orgId, projectId, vpcId, *st.Id, *st) + err = nsxutil.NSXApiError(err) if err != nil { return err } return nil } -func (service *StaticRouteService) DeleteStaticRouteByPath(orgId string, projectId string, vpcId string, uid string) error { +func (service *StaticRouteService) DeleteStaticRouteByPath(orgId string, projectId string, vpcId string, id string) error { staticRouteClient := service.NSXClient.StaticRouteClient - staticroute := service.StaticRouteStore.GetByKey(uid) + staticroute := service.StaticRouteStore.GetByKey(id) if staticroute == nil { return nil } if err := staticRouteClient.Delete(orgId, projectId, vpcId, *staticroute.Id); err != nil { + err = nsxutil.NSXApiError(err) return err } if err := service.StaticRouteStore.Delete(staticroute); err != nil { @@ -131,12 +135,17 @@ func (service *StaticRouteService) GetUID(staticroute *model.StaticRoutes) *stri } -func (service *StaticRouteService) DeleteStaticRoute(namespace string, uid string) error { - vpc := service.VPCService.ListVPCInfo(namespace) - if len(vpc) == 0 { +func (service *StaticRouteService) DeleteStaticRoute(obj *v1alpha1.StaticRoute) error { + id := util.GenerateIDByObject(obj) + staticroute := service.StaticRouteStore.GetByKey(id) + if staticroute == nil { return nil } - return service.DeleteStaticRouteByPath(vpc[0].OrgID, vpc[0].ProjectID, vpc[0].ID, uid) + vpcResourceInfo, err := common.ParseVPCResourcePath(*staticroute.Path) + if err != nil { + return err + } + return service.DeleteStaticRouteByPath(vpcResourceInfo.OrgID, vpcResourceInfo.ProjectID, vpcResourceInfo.ID, id) } func (service *StaticRouteService) ListStaticRoute() []*model.StaticRoutes { diff --git a/pkg/nsx/services/staticroute/staticroute_test.go b/pkg/nsx/services/staticroute/staticroute_test.go index c66fe4757..5cbc4ab5c 100644 --- a/pkg/nsx/services/staticroute/staticroute_test.go +++ b/pkg/nsx/services/staticroute/staticroute_test.go @@ -12,10 +12,11 @@ import ( "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" "github.com/vmware/vsphere-automation-sdk-go/runtime/data" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/cache" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mocks "github.com/vmware-tanzu/nsx-operator/pkg/mock/staticrouteclient" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" @@ -128,25 +129,26 @@ func TestStaticRouteService_DeleteStaticRoute(t *testing.T) { t.Error(err) } - id := "vpc-1" - sr1 := &model.StaticRoutes{Id: &id} - - returnservice.StaticRouteStore.Add(sr1) - - patches := gomonkey.ApplyMethod(reflect.TypeOf(returnservice.VPCService), "ListVPCInfo", func(_ common.VPCServiceProvider, ns string) []common.VPCResourceInfo { - id := "vpc-1" - return []common.VPCResourceInfo{{OrgID: "default", ProjectID: "project-1", VPCID: "vpc-1", ID: id}} - }) + srObj := &v1alpha1.StaticRoute{ + ObjectMeta: v1.ObjectMeta{ + UID: "uid-123", + Name: "sr", + }, + } + id := "sr-uid-123" + path := "/orgs/default/projects/project-1/vpcs/vpc-1" + sr1 := &model.StaticRoutes{Id: &id, Path: &path} // no record found mockStaticRouteclient.EXPECT().Delete(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Times(0) - err = returnservice.DeleteStaticRoute("123", "vpc1") + err = returnservice.DeleteStaticRoute(srObj) assert.Equal(t, err, nil) - defer patches.Reset() + + returnservice.StaticRouteStore.Add(sr1) // delete record mockStaticRouteclient.EXPECT().Delete("default", "project-1", "vpc-1", id).Return(nil).Times(1) - err = returnservice.DeleteStaticRoute("123", id) + err = returnservice.DeleteStaticRoute(srObj) assert.Equal(t, err, nil) srs := returnservice.StaticRouteStore.List() assert.Equal(t, len(srs), 0) diff --git a/pkg/nsx/services/subnet/builder.go b/pkg/nsx/services/subnet/builder.go index 5d9eb1e66..7333d59fc 100644 --- a/pkg/nsx/services/subnet/builder.go +++ b/pkg/nsx/services/subnet/builder.go @@ -3,44 +3,54 @@ package subnet import ( "fmt" - "github.com/google/uuid" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" util2 "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) +const AccessModeProjectInNSX string = "Private_TGW" + var ( String = common.String Int64 = common.Int64 Bool = common.Bool ) -const ( - SUBNETPREFIX = "sub" -) - func getCluster(service *SubnetService) string { return service.NSXConfig.Cluster } func (service *SubnetService) BuildSubnetID(subnet *v1alpha1.Subnet) string { - return util.GenerateID(string(subnet.UID), SUBNETPREFIX, "", "") + return util.GenerateIDByObject(subnet) } func (service *SubnetService) buildSubnetSetID(subnetset *v1alpha1.SubnetSet, index string) string { - return util.GenerateID(string(subnetset.UID), SUBNETPREFIX, "", index) + return util.GenerateIDByObjectWithSuffix(subnetset, index) } +// buildSubnetName uses format "subnet.Name-subnet.UUID" to ensure the Subnet's display_name is not +// conflict with others. This is because VC will use the Subnet's display_name to created folder, so +// the name string must be unique. func (service *SubnetService) buildSubnetName(subnet *v1alpha1.Subnet) string { - return util.GenerateTruncName(common.MaxSubnetNameLength, subnet.ObjectMeta.Name, SUBNETPREFIX, "", "", getCluster(service)) + return util.GenerateIDByObjectByLimit(subnet, common.MaxSubnetNameLength) } +// buildSubnetSetName uses format "subnetset.Name-subnetset.UUID-index" to ensure the generated Subnet's +// display_name is not conflict with others. func (service *SubnetService) buildSubnetSetName(subnetset *v1alpha1.SubnetSet, index string) string { - return util.GenerateTruncName(common.MaxSubnetNameLength, subnetset.ObjectMeta.Name, SUBNETPREFIX, index, "", getCluster(service)) + resName := util.GenerateIDByObjectByLimit(subnetset, common.MaxSubnetNameLength-(len(index)+1)) + return util.GenerateTruncName(common.MaxSubnetNameLength, resName, "", index, "", "") +} + +func convertAccessMode(accessMode string) string { + if accessMode == v1alpha1.AccessModeProject { + return AccessModeProjectInNSX + } + return accessMode } func (service *SubnetService) buildSubnet(obj client.Object, tags []model.Tag) (*model.VpcSubnet, error) { @@ -50,22 +60,26 @@ func (service *SubnetService) buildSubnet(obj client.Object, tags []model.Tag) ( switch o := obj.(type) { case *v1alpha1.Subnet: nsxSubnet = &model.VpcSubnet{ - Id: String(service.BuildSubnetID(o)), - AccessMode: String(util.Capitalize(string(o.Spec.AccessMode))), - DhcpConfig: service.buildDHCPConfig(o.Spec.DHCPConfig.EnableDHCP, int64(o.Spec.IPv4SubnetSize-4)), - DisplayName: String(service.buildSubnetName(o)), + Id: String(service.BuildSubnetID(o)), + AccessMode: String(convertAccessMode(util.Capitalize(string(o.Spec.AccessMode)))), + Ipv4SubnetSize: Int64(int64(o.Spec.IPv4SubnetSize)), + DhcpConfig: service.buildDHCPConfig(o.Spec.DHCPConfig.EnableDHCP, int64(o.Spec.IPv4SubnetSize-4)), + DisplayName: String(service.buildSubnetName(o)), } - staticIpAllocation = o.Spec.AdvancedConfig.StaticIPAllocation.Enable + staticIpAllocation = !o.Spec.DHCPConfig.EnableDHCP nsxSubnet.IpAddresses = o.Spec.IPAddresses case *v1alpha1.SubnetSet: - index := uuid.NewString() + // The index is a random string with the length of 8 chars. It is the first 8 chars of the hash + // value on a random UUID string. + index := util.GetRandomIndexString() nsxSubnet = &model.VpcSubnet{ - Id: String(service.buildSubnetSetID(o, index)), - AccessMode: String(util.Capitalize(string(o.Spec.AccessMode))), - DhcpConfig: service.buildDHCPConfig(o.Spec.DHCPConfig.EnableDHCP, int64(o.Spec.IPv4SubnetSize-4)), - DisplayName: String(service.buildSubnetSetName(o, index)), + Id: String(service.buildSubnetSetID(o, index)), + AccessMode: String(convertAccessMode(util.Capitalize(string(o.Spec.AccessMode)))), + Ipv4SubnetSize: Int64(int64(o.Spec.IPv4SubnetSize)), + DhcpConfig: service.buildDHCPConfig(o.Spec.DHCPConfig.EnableDHCP, int64(o.Spec.IPv4SubnetSize-4)), + DisplayName: String(service.buildSubnetSetName(o, index)), } - staticIpAllocation = o.Spec.AdvancedConfig.StaticIPAllocation.Enable + staticIpAllocation = !o.Spec.DHCPConfig.EnableDHCP default: return nil, SubnetTypeError } @@ -88,12 +102,14 @@ func (service *SubnetService) buildDHCPConfig(enableDHCP bool, poolSize int64) * // otherwise Subnet will use DhcpConfig inherited from VPC. dhcpConfig := &model.VpcSubnetDhcpConfig{ EnableDhcp: Bool(enableDHCP), - StaticPoolConfig: &model.StaticPoolConfig{ + } + if !enableDHCP { + dhcpConfig.StaticPoolConfig = &model.StaticPoolConfig{ // Number of IPs to be reserved in static ip pool. // By default, if dhcp is enabled then static ipv4 pool size will be zero and all available IPs will be // reserved in local dhcp pool. Maximum allowed value is 'subnet size - 4'. Ipv4PoolSize: Int64(poolSize), - }, + } } return dhcpConfig } diff --git a/pkg/nsx/services/subnet/builder_test.go b/pkg/nsx/services/subnet/builder_test.go new file mode 100644 index 000000000..f269aad28 --- /dev/null +++ b/pkg/nsx/services/subnet/builder_test.go @@ -0,0 +1,62 @@ +package subnet + +import ( + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/config" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func TestBuildSubnetName(t *testing.T) { + svc := &SubnetService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "cluster1", + }, + }, + }, + } + subnet := &v1alpha1.Subnet{ + ObjectMeta: v1.ObjectMeta{ + UID: "uuid1", + Name: "subnet1", + }, + } + name := svc.buildSubnetName(subnet) + expName := "subnet1-uuid1" + assert.Equal(t, expName, name) + id := svc.BuildSubnetID(subnet) + expId := "subnet1-uuid1" + assert.Equal(t, expId, id) +} + +func TestBuildSubnetSetName(t *testing.T) { + svc := &SubnetService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "b720ee2c-5788-4680-9796-0f93db33d8a9", + }, + }, + }, + } + subnetset := &v1alpha1.SubnetSet{ + ObjectMeta: v1.ObjectMeta{ + UID: "28e85c0b-21e4-4cab-b1c3-597639dfe752", + Name: "pod-default", + }, + } + index := "0c5d588b" + name := svc.buildSubnetSetName(subnetset, index) + expName := "pod-default-28e85c0b-21e4-4cab-b1c3-597639dfe752-0c5d588b" + assert.Equal(t, expName, name) + assert.True(t, len(name) <= 80) + id := svc.buildSubnetSetID(subnetset, index) + expId := "pod-default-28e85c0b-21e4-4cab-b1c3-597639dfe752_0c5d588b" + assert.Equal(t, expId, id) +} diff --git a/pkg/nsx/services/subnet/subnet.go b/pkg/nsx/services/subnet/subnet.go index 0c948a9fb..f7efffcbf 100644 --- a/pkg/nsx/services/subnet/subnet.go +++ b/pkg/nsx/services/subnet/subnet.go @@ -16,7 +16,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/realizestate" @@ -24,7 +24,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log MarkedForDelete = true EnforceRevisionCheckParam = false ResourceTypeSubnet = common.ResourceTypeSubnet @@ -111,10 +111,12 @@ func (service *SubnetService) createOrUpdateSubnet(obj client.Object, nsxSubnet return "", err } if err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam); err != nil { + err = nsxutil.NSXApiError(err) return "", err } // Get Subnet from NSX after patch operation as NSX renders several fields like `path`/`parent_path`. if *nsxSubnet, err = service.NSXClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, *nsxSubnet.Id); err != nil { + err = nsxutil.NSXApiError(err) return "", err } realizeService := realizestate.InitializeRealizeState(service.Service) @@ -151,6 +153,7 @@ func (service *SubnetService) DeleteSubnet(nsxSubnet model.VpcSubnet) error { return err } if err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam); err != nil { + err = nsxutil.NSXApiError(err) // Subnets that are not deleted successfully will finally be deleted by GC. log.Error(err, "failed to delete Subnet", "ID", *nsxSubnet.Id) return err @@ -198,12 +201,14 @@ func (service *SubnetService) IsOrphanSubnet(subnet model.VpcSubnet, subnetsetID func (service *SubnetService) DeleteIPAllocation(orgID, projectID, vpcID, subnetID string) error { ipAllocations, err := service.NSXClient.IPAllocationClient.List(orgID, projectID, vpcID, subnetID, ipPoolID, nil, nil, nil, nil, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get ip-allocations", "Subnet", subnetID) return err } for _, alloc := range ipAllocations.Results { if err = service.NSXClient.IPAllocationClient.Delete(orgID, projectID, vpcID, subnetID, ipPoolID, *alloc.Id); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete ip-allocation", "Subnet", subnetID, "ip-alloc", *alloc.Id) return err } @@ -218,6 +223,7 @@ func (service *SubnetService) GetSubnetStatus(subnet *model.VpcSubnet) ([]model. return nil, err } statusList, err := service.NSXClient.SubnetStatusClient.List(param.OrgID, param.ProjectID, param.VPCID, *subnet.Id) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get subnet status") return nil, err @@ -227,6 +233,11 @@ func (service *SubnetService) GetSubnetStatus(subnet *model.VpcSubnet) ([]model. log.Error(err, "no subnet status found") return nil, err } + if statusList.Results[0].NetworkAddress == nil || statusList.Results[0].GatewayAddress == nil { + err := fmt.Errorf("invalid status result: %+v", statusList.Results[0]) + log.Error(err, "subnet status does not have network address or gateway address", "subnet.Id", subnet.Id) + return nil, err + } return statusList.Results, nil } @@ -236,6 +247,7 @@ func (service *SubnetService) getIPPoolUsage(nsxSubnet *model.VpcSubnet) (*model return nil, err } ipPool, err := service.NSXClient.IPPoolClient.Get(param.OrgID, param.ProjectID, param.VPCID, *nsxSubnet.Id, ipPoolID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get ip-pool", "Subnet", *nsxSubnet.Id) return nil, err @@ -260,11 +272,14 @@ func (service *SubnetService) UpdateSubnetSetStatus(obj *v1alpha1.SubnetSet) err if err != nil { return err } - subnetInfo := v1alpha1.SubnetInfo{ - NSXResourcePath: *subnet.Path, - } + subnetInfo := v1alpha1.SubnetInfo{} for _, status := range statusList { - subnetInfo.IPAddresses = append(subnetInfo.IPAddresses, *status.NetworkAddress) + subnetInfo.NetworkAddresses = append(subnetInfo.NetworkAddresses, *status.NetworkAddress) + subnetInfo.GatewayAddresses = append(subnetInfo.GatewayAddresses, *status.GatewayAddress) + // DHCPServerAddress is only for the subnet with DHCP enabled + if status.DhcpServerAddress != nil { + subnetInfo.DHCPServerAddresses = append(subnetInfo.DHCPServerAddresses, *status.DhcpServerAddress) + } } subnetInfoList = append(subnetInfoList, subnetInfo) } diff --git a/pkg/nsx/services/subnetport/builder.go b/pkg/nsx/services/subnetport/builder.go index dd39f83fa..0c8795f94 100644 --- a/pkg/nsx/services/subnetport/builder.go +++ b/pkg/nsx/services/subnetport/builder.go @@ -7,11 +7,14 @@ import ( "github.com/google/uuid" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + controllercommon "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) @@ -21,31 +24,33 @@ var ( ) func (service *SubnetPortService) buildSubnetPort(obj interface{}, nsxSubnet *model.VpcSubnet, contextID string, labelTags *map[string]string) (*model.VpcSubnetPort, error) { - var objName, objNamespace, uid, appId, allocateAddresses string + var objNamespace, appId, allocateAddresses string + objMeta := getObjectMeta(obj) + if objMeta == nil { + return nil, fmt.Errorf("unsupported object: %v", obj) + } + objNamespace = objMeta.Namespace + if _, ok := obj.(*corev1.Pod); ok { + appId = string(objMeta.UID) + } + var externalAddressBinding *model.ExternalAddressBinding switch o := obj.(type) { case *v1alpha1.SubnetPort: - objName = o.Name - objNamespace = o.Namespace - uid = string(o.UID) - case *corev1.Pod: - objName = o.Name - objNamespace = o.Namespace - uid = string(o.UID) - appId = string(o.UID) + externalAddressBinding = service.buildExternalAddressBinding(o) } - if *nsxSubnet.DhcpConfig.EnableDhcp { + if nsxSubnet.DhcpConfig != nil && nsxSubnet.DhcpConfig.EnableDhcp != nil && *nsxSubnet.DhcpConfig.EnableDhcp { allocateAddresses = "DHCP" } else { allocateAddresses = "BOTH" } - nsxSubnetPortName := util.GenerateDisplayName(objName, "port", "", "", "") - nsxSubnetPortID := util.GenerateID(uid, "", "", "") + nsxSubnetPortName := service.BuildSubnetPortName(objMeta) + nsxSubnetPortID := service.BuildSubnetPortId(objMeta) // use the subnetPort CR UID as the attachment uid generation to ensure the latter stable - nsxCIFID, err := uuid.NewRandomFromReader(bytes.NewReader([]byte(nsxSubnetPortID))) + nsxCIFID, err := uuid.NewRandomFromReader(bytes.NewReader([]byte(string(objMeta.UID)))) if err != nil { return nil, err } - nsxSubnetPortPath := fmt.Sprintf("%s/ports/%s", *nsxSubnet.Path, uid) + nsxSubnetPortPath := fmt.Sprintf("%s/ports/%s", *nsxSubnet.Path, nsxSubnetPortID) if err != nil { return nil, err } @@ -72,9 +77,10 @@ func (service *SubnetPortService) buildSubnetPort(obj interface{}, nsxSubnet *mo TrafficTag: common.Int64(0), Type_: String("STATIC"), }, - Tags: tags, - Path: &nsxSubnetPortPath, - ParentPath: nsxSubnet.Path, + Tags: tags, + Path: &nsxSubnetPortPath, + ParentPath: nsxSubnet.Path, + ExternalAddressBinding: externalAddressBinding, } if appId != "" { nsxSubnetPort.Attachment.AppId = &appId @@ -83,6 +89,82 @@ func (service *SubnetPortService) buildSubnetPort(obj interface{}, nsxSubnet *mo return nsxSubnetPort, nil } +func (service *SubnetPortService) BuildSubnetPortId(obj *metav1.ObjectMeta) string { + return util.GenerateIDByObject(obj) +} + +func (service *SubnetPortService) BuildSubnetPortName(obj *metav1.ObjectMeta) string { + return util.GenerateTruncName(common.MaxNameLength, obj.Name, "", "", "", "") +} + +func getObjectMeta(obj interface{}) *metav1.ObjectMeta { + switch o := obj.(type) { + case *v1alpha1.SubnetPort: + return &o.ObjectMeta + case *corev1.Pod: + return &o.ObjectMeta + } + return nil +} + func getCluster(service *SubnetPortService) string { return service.NSXConfig.Cluster } + +func buildSubnetPortExternalAddressBindingFromExisting(subnetPort *model.VpcSubnetPort, existingSubnetPort *model.VpcSubnetPort) *model.VpcSubnetPort { + if existingSubnetPort == nil { + return subnetPort + } + if existingSubnetPort.ExternalAddressBinding != nil { + if subnetPort.ExternalAddressBinding != nil { + // update is not supported, keep existing ExternalAddressBinding + subnetPort.ExternalAddressBinding = &model.ExternalAddressBinding{} + } + } + return subnetPort +} + +func (service *SubnetPortService) buildExternalAddressBinding(sp *v1alpha1.SubnetPort) *model.ExternalAddressBinding { + if service.GetAddressBindingBySubnetPort(sp) != nil { + return &model.ExternalAddressBinding{} + } + return nil +} + +func (service *SubnetPortService) GetAddressBindingBySubnetPort(sp *v1alpha1.SubnetPort) *v1alpha1.AddressBinding { + vm, port, err := controllercommon.GetVirtualMachineNameForSubnetPort(sp) + if err != nil { + log.Error(err, "Failed to get VM name from SubnetPort", "namespace", sp.Namespace, "name", sp.Name, "annotations", sp.Annotations) + return nil + } else if vm == "" { + log.Info("Failed to get VM name from SubnetPort", "namespace", sp.Namespace, "name", sp.Name, "annotations", sp.Annotations) + return nil + } + abList := &v1alpha1.AddressBindingList{} + abIndexValue := fmt.Sprintf("%s/%s", sp.Namespace, vm) + err = service.Client.List(context.TODO(), abList, client.MatchingFields{util.AddressBindingNamespaceVMIndexKey: abIndexValue}) + if err != nil { + log.Error(err, "Failed to list AddressBinding from cache", "indexValue", abIndexValue) + return nil + } + for _, ab := range abList.Items { + if ab.Spec.InterfaceName == "" { + spList := &v1alpha1.SubnetPortList{} + spIndexValue := fmt.Sprintf("%s/%s", ab.Namespace, ab.Spec.VMName) + err = service.Client.List(context.TODO(), spList, client.MatchingFields{util.SubnetPortNamespaceVMIndexKey: spIndexValue}) + if err != nil || len(spList.Items) == 0 { + log.Error(err, "Failed to list SubnetPort from cache", "indexValue", spIndexValue) + return nil + } + if len(spList.Items) == 1 { + log.Info("Found default AddressBinding for SubnetPort", "namespace", sp.Namespace, "name", sp.Name, "defaultAddressBindingName", ab.Name, "VM", vm) + return &ab + } + log.Info("Found multiple SubnetPorts for a VM, ignore default AddressBinding for SubnetPort", "namespace", sp.Namespace, "name", sp.Name, "defaultAddressBindingName", ab.Name, "VM", vm) + } else if ab.Spec.InterfaceName == port { + log.V(1).Info("Found AddressBinding for SubnetPort", "namespace", sp.Namespace, "name", sp.Name, "addressBindingName", ab.Name) + return &ab + } + } + return nil +} diff --git a/pkg/nsx/services/subnetport/builder_test.go b/pkg/nsx/services/subnetport/builder_test.go index fa1a8bd09..b7be31503 100644 --- a/pkg/nsx/services/subnetport/builder_test.go +++ b/pkg/nsx/services/subnetport/builder_test.go @@ -11,7 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" @@ -40,7 +40,7 @@ func TestBuildSubnetPort(t *testing.T) { k8sClient.EXPECT().Get(ctx, gomock.Any(), namespace).Return(nil).Do( func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { return nil - }) + }).AnyTimes() tests := []struct { name string @@ -52,7 +52,7 @@ func TestBuildSubnetPort(t *testing.T) { expectedError error }{ { - name: "01", + name: "build-NSX-port-for-subnetport", obj: &v1alpha1.SubnetPort{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1alpha1", @@ -73,8 +73,8 @@ func TestBuildSubnetPort(t *testing.T) { contextID: "fake_context_id", labelTags: nil, expectedPort: &model.VpcSubnetPort{ - DisplayName: common.String("port-fake_subnetport"), - Id: common.String("2ccec3b9-7546-4fd2-812a-1e3a4afd7acc"), + DisplayName: common.String("fake_subnetport"), + Id: common.String("fake_subnetport-2ccec3b9-7546-4fd2-812a-1e3a4afd7acc"), Tags: []model.Tag{ { Scope: common.String("nsx-op/cluster"), @@ -97,7 +97,7 @@ func TestBuildSubnetPort(t *testing.T) { Tag: common.String("2ccec3b9-7546-4fd2-812a-1e3a4afd7acc"), }, }, - Path: common.String("fake_path/ports/2ccec3b9-7546-4fd2-812a-1e3a4afd7acc"), + Path: common.String("fake_path/ports/fake_subnetport-2ccec3b9-7546-4fd2-812a-1e3a4afd7acc"), ParentPath: common.String("fake_path"), Attachment: &model.PortAttachment{ AllocateAddresses: common.String("DHCP"), @@ -108,6 +108,65 @@ func TestBuildSubnetPort(t *testing.T) { }, expectedError: nil, }, + { + name: "build-NSX-port-for-pod", + obj: &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + UID: "c5db1800-ce4c-11de-a935-8105ba7ace78", + Name: "fake_pod", + Namespace: "fake_ns", + }, + }, + nsxSubnet: &model.VpcSubnet{ + DhcpConfig: &model.VpcSubnetDhcpConfig{ + EnableDhcp: common.Bool(true), + }, + Path: common.String("fake_path"), + }, + contextID: "fake_context_id", + labelTags: nil, + expectedPort: &model.VpcSubnetPort{ + DisplayName: common.String("fake_pod"), + Id: common.String("fake_pod-c5db1800-ce4c-11de-a935-8105ba7ace78"), + Tags: []model.Tag{ + { + Scope: common.String("nsx-op/cluster"), + Tag: common.String("fake_cluster"), + }, + { + Scope: common.String("nsx-op/version"), + Tag: common.String("1.0.0"), + }, + { + Scope: common.String("nsx-op/namespace"), + Tag: common.String("fake_ns"), + }, + { + Scope: common.String("nsx-op/pod_name"), + Tag: common.String("fake_pod"), + }, + { + Scope: common.String("nsx-op/pod_uid"), + Tag: common.String("c5db1800-ce4c-11de-a935-8105ba7ace78"), + }, + }, + Path: common.String("fake_path/ports/fake_pod-c5db1800-ce4c-11de-a935-8105ba7ace78"), + ParentPath: common.String("fake_path"), + Attachment: &model.PortAttachment{ + AllocateAddresses: common.String("DHCP"), + Type_: common.String("STATIC"), + Id: common.String("63356462-3138-4030-ad63-6534632d3131"), + TrafficTag: common.Int64(0), + AppId: common.String("c5db1800-ce4c-11de-a935-8105ba7ace78"), + ContextId: common.String("fake_context_id"), + }, + }, + expectedError: nil, + }, } for _, tt := range tests { diff --git a/pkg/nsx/services/subnetport/compare.go b/pkg/nsx/services/subnetport/compare.go index d2c43a9b0..79384b7dd 100644 --- a/pkg/nsx/services/subnetport/compare.go +++ b/pkg/nsx/services/subnetport/compare.go @@ -36,6 +36,10 @@ func (sp *SubnetPort) Value() data.DataValue { Type_: sp.Attachment.AllocateAddresses, } } + // only check existence of ExternalAddressBinding + if sp.ExternalAddressBinding != nil { + s.ExternalAddressBinding = &model.ExternalAddressBinding{} + } dataValue, _ := ComparableToSubnetPort(s).GetDataValue__() return dataValue } diff --git a/pkg/nsx/services/subnetport/store.go b/pkg/nsx/services/subnetport/store.go index c9c7464cd..6a01e4d68 100644 --- a/pkg/nsx/services/subnetport/store.go +++ b/pkg/nsx/services/subnetport/store.go @@ -16,6 +16,8 @@ func keyFunc(obj interface{}) (string, error) { return *v.Id, nil case types.UID: return string(v), nil + case string: + return v, nil default: return "", errors.New("keyFunc doesn't support unknown type") } diff --git a/pkg/nsx/services/subnetport/subnetport.go b/pkg/nsx/services/subnetport/subnetport.go index def0987ee..783cf5181 100644 --- a/pkg/nsx/services/subnetport/subnetport.go +++ b/pkg/nsx/services/subnetport/subnetport.go @@ -6,17 +6,18 @@ package subnetport import ( "context" "errors" + "fmt" "sync" "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/realizestate" @@ -25,7 +26,7 @@ import ( ) var ( - log = logger.Log + log = &logger.Log ResourceTypeSubnetPort = servicecommon.ResourceTypeSubnetPort MarkedForDelete = true ) @@ -91,18 +92,24 @@ func (service *SubnetPortService) CreateOrUpdateSubnetPort(obj interface{}, nsxS existingSubnetPort := service.SubnetPortStore.GetByKey(*nsxSubnetPort.Id) isChanged := true if existingSubnetPort != nil { + // The existing port's attachment ID should not be changed in any case. + if existingSubnetPort.Attachment != nil { + nsxSubnetPort.Attachment.Id = existingSubnetPort.Attachment.Id + } isChanged = servicecommon.CompareResource(SubnetPortToComparable(existingSubnetPort), SubnetPortToComparable(nsxSubnetPort)) } + subnetInfo, err := servicecommon.ParseVPCResourcePath(*nsxSubnet.Path) + if err != nil { + return nil, err + } if !isChanged { log.Info("NSX subnet port not changed, skipping the update", "nsxSubnetPort.Id", nsxSubnetPort.Id, "nsxSubnetPath", *nsxSubnet.Path) // We don't need to update it but still need to check realized state. } else { + nsxSubnetPort = buildSubnetPortExternalAddressBindingFromExisting(nsxSubnetPort, existingSubnetPort) log.Info("updating the NSX subnet port", "existingSubnetPort", existingSubnetPort, "desiredSubnetPort", nsxSubnetPort) - subnetInfo, err := servicecommon.ParseVPCResourcePath(*nsxSubnet.Path) - if err != nil { - return nil, err - } err = service.NSXClient.PortClient.Patch(subnetInfo.OrgID, subnetInfo.ProjectID, subnetInfo.VPCID, subnetInfo.ID, *nsxSubnetPort.Id, *nsxSubnetPort) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create or update subnet port", "nsxSubnetPort.Id", *nsxSubnetPort.Id, "nsxSubnetPath", *nsxSubnet.Path) return nil, err @@ -126,6 +133,15 @@ func (service *SubnetPortService) CreateOrUpdateSubnetPort(obj interface{}, nsxS log.Error(err, "check and update NSX subnet port state failed, would retry exponentially", "nsxSubnetPort.Id", *nsxSubnetPort.Id, "nsxSubnetPath", *nsxSubnet.Path) return nil, err } + createdNSXSubnetPort, err := service.NSXClient.PortClient.Get(subnetInfo.OrgID, subnetInfo.ProjectID, subnetInfo.VPCID, subnetInfo.ID, *nsxSubnetPort.Id) + if err != nil { + log.Error(err, "check and update NSX subnet port failed, would retry exponentially", "nsxSubnetPort.Id", *nsxSubnetPort.Id, "nsxSubnetPath", *nsxSubnet.Path) + return nil, err + } + err = service.SubnetPortStore.Apply(&createdNSXSubnetPort) + if err != nil { + return nil, err + } if isChanged { log.Info("successfully created or updated subnetport", "nsxSubnetPort.Id", *nsxSubnetPort.Id) } else { @@ -136,14 +152,15 @@ func (service *SubnetPortService) CreateOrUpdateSubnetPort(obj interface{}, nsxS // CheckSubnetPortState will check the port realized status then get the port state to prepare the CR status. func (service *SubnetPortService) CheckSubnetPortState(obj interface{}, nsxSubnetPath string, enableDHCP bool) (*model.SegmentPortState, error) { - var uid types.UID + var objMeta metav1.ObjectMeta switch o := obj.(type) { case *v1alpha1.SubnetPort: - uid = o.UID + objMeta = o.ObjectMeta case *v1.Pod: - uid = o.UID + objMeta = o.ObjectMeta } - nsxSubnetPort := service.SubnetPortStore.GetByKey(string(uid)) + portID := util.GenerateIDByObject(&objMeta) + nsxSubnetPort := service.SubnetPortStore.GetByKey(portID) if nsxSubnetPort == nil { return nil, errors.New("failed to get subnet port from store") } @@ -157,10 +174,10 @@ func (service *SubnetPortService) CheckSubnetPortState(obj interface{}, nsxSubne if err := realizeService.CheckRealizeState(backoff, *nsxSubnetPort.Path, "RealizedLogicalPort"); err != nil { log.Error(err, "failed to get realized status", "subnetport path", *nsxSubnetPort.Path) if realizestate.IsRealizeStateError(err) { - log.Error(err, "the created subnet port is in error realization state, cleaning the resource", "subnetport", uid) + log.Error(err, "the created subnet port is in error realization state, cleaning the resource", "subnetport", portID) // only recreate subnet port on RealizationErrorStateError. - if err := service.DeleteSubnetPort(uid); err != nil { - log.Error(err, "cleanup error subnetport failed", "subnetport", uid) + if err := service.DeleteSubnetPort(portID); err != nil { + log.Error(err, "cleanup error subnetport failed", "subnetport", portID) return nil, err } } @@ -171,7 +188,7 @@ func (service *SubnetPortService) CheckSubnetPortState(obj interface{}, nsxSubne if err != nil { return nil, err } - log.Info("got the NSX subnet port state", "nsxPortState.RealizedBindings", nsxPortState.RealizedBindings, "uid", uid) + log.Info("got the NSX subnet port state", "nsxPortState.RealizedBindings", nsxPortState.RealizedBindings, "uid", portID) if len(nsxPortState.RealizedBindings) == 0 && !enableDHCP { return nsxPortState, errors.New("empty realized bindings") } @@ -179,50 +196,60 @@ func (service *SubnetPortService) CheckSubnetPortState(obj interface{}, nsxSubne } func (service *SubnetPortService) GetSubnetPortState(obj interface{}, nsxSubnetPath string) (*model.SegmentPortState, error) { - var uid types.UID + var nsxSubnetPortID string switch o := obj.(type) { case *v1alpha1.SubnetPort: - uid = o.UID + nsxSubnetPortID = service.BuildSubnetPortId(&o.ObjectMeta) case *v1.Pod: - uid = o.UID + nsxSubnetPortID = service.BuildSubnetPortId(&o.ObjectMeta) } nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID := nsxutil.ParseVPCPath(nsxSubnetPath) - nsxSubnetPortState, err := service.NSXClient.PortStateClient.Get(nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID, string(uid), nil, nil) + nsxSubnetPortState, err := service.NSXClient.PortStateClient.Get(nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID, nsxSubnetPortID, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { - log.Error(err, "failed to get subnet port state", "nsxSubnetPortID", uid, "nsxSubnetPath", nsxSubnetPath) + log.Error(err, "failed to get subnet port state", "nsxSubnetPortID", nsxSubnetPortID, "nsxSubnetPath", nsxSubnetPath) return nil, err } return &nsxSubnetPortState, nil } -func (service *SubnetPortService) DeleteSubnetPort(uid types.UID) error { - nsxSubnetPort := service.SubnetPortStore.GetByKey(string(uid)) +func (service *SubnetPortService) DeleteSubnetPort(portID string) error { + nsxSubnetPort := service.SubnetPortStore.GetByKey(portID) if nsxSubnetPort == nil || nsxSubnetPort.Id == nil { - log.Info("NSX subnet port is not found in store, skip deleting it", "uid", uid) + log.Info("NSX subnet port is not found in store, skip deleting it", "id", portID) return nil } nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID := nsxutil.ParseVPCPath(*nsxSubnetPort.Path) - err := service.NSXClient.PortClient.Delete(nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID, string(uid)) + err := service.NSXClient.PortClient.Delete(nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID, portID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to delete subnetport", "nsxSubnetPort.Path", *nsxSubnetPort.Path) return err } - if err = service.SubnetPortStore.Delete(uid); err != nil { + if err = service.SubnetPortStore.Delete(portID); err != nil { return err } - log.Info("successfully deleted nsxSubnetPort", "nsxSubnetPortID", uid) + log.Info("successfully deleted nsxSubnetPort", "nsxSubnetPortID", portID) return nil } func (service *SubnetPortService) ListNSXSubnetPortIDForCR() sets.Set[string] { log.V(2).Info("listing subnet port CR UIDs") - subnetPortSet := service.SubnetPortStore.ListIndexFuncValues(servicecommon.TagScopeSubnetPortCRUID) + subnetPortSet := sets.New[string]() + for _, subnetPortCRUid := range service.SubnetPortStore.ListIndexFuncValues(servicecommon.TagScopeSubnetPortCRUID).UnsortedList() { + subnetPortIDs, _ := service.SubnetPortStore.IndexKeys(servicecommon.TagScopeSubnetPortCRUID, subnetPortCRUid) + subnetPortSet.Insert(subnetPortIDs...) + } return subnetPortSet } func (service *SubnetPortService) ListNSXSubnetPortIDForPod() sets.Set[string] { log.V(2).Info("listing pod UIDs") - subnetPortSet := service.SubnetPortStore.ListIndexFuncValues(servicecommon.TagScopePodUID) + subnetPortSet := sets.New[string]() + for _, podUID := range service.SubnetPortStore.ListIndexFuncValues(servicecommon.TagScopePodUID).UnsortedList() { + subnetPortIDs, _ := service.SubnetPortStore.IndexKeys(servicecommon.TagScopePodUID, podUID) + subnetPortSet.Insert(subnetPortIDs...) + } return subnetPortSet } @@ -234,6 +261,7 @@ func (service *SubnetPortService) GetGatewayPrefixForSubnetPort(obj *v1alpha1.Su } // TODO: if the port is not the first on the same subnet, try to get the info from existing realized subnetport CR to avoid query NSX API again. statusList, err := service.NSXClient.SubnetStatusClient.List(subnetInfo.OrgID, subnetInfo.ProjectID, subnetInfo.VPCID, subnetInfo.ID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get subnet status") return "", -1, err @@ -244,6 +272,11 @@ func (service *SubnetPortService) GetGatewayPrefixForSubnetPort(obj *v1alpha1.Su return "", -1, err } status := statusList.Results[0] + if status.GatewayAddress == nil { + err := fmt.Errorf("invalid status result: %+v", status) + log.Error(err, "subnet status does not have gateway address", "nsxSubnetPath", nsxSubnetPath) + return "", -1, err + } gateway, err := util.RemoveIPPrefix(*status.GatewayAddress) if err != nil { return "", -1, err @@ -276,7 +309,7 @@ func (service *SubnetPortService) Cleanup(ctx context.Context) error { subnetPorts := service.SubnetPortStore.List() log.Info("cleanup subnetports", "count", len(subnetPorts)) for _, subnetPort := range subnetPorts { - subnetPortID := types.UID(*subnetPort.(*model.VpcSubnetPort).Id) + subnetPortID := *subnetPort.(*model.VpcSubnetPort).Id select { case <-ctx.Done(): return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) diff --git a/pkg/nsx/services/subnetport/subnetport_test.go b/pkg/nsx/services/subnetport/subnetport_test.go new file mode 100644 index 000000000..820fb457d --- /dev/null +++ b/pkg/nsx/services/subnetport/subnetport_test.go @@ -0,0 +1,117 @@ +package subnetport + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func TestListNSXSubnetPortIDForCR(t *testing.T) { + subnetPortService := createSubnetPortService() + crName := "fake_subnetport" + crUUID := "2ccec3b9-7546-4fd2-812a-1e3a4afd7acc" + subnetPortByCR := &model.VpcSubnetPort{ + DisplayName: common.String(crName), + Id: common.String(fmt.Sprintf("%s-%s", crName, crUUID)), + Tags: []model.Tag{ + { + Scope: common.String("nsx-op/cluster"), + Tag: common.String("fake_cluster"), + }, + { + Scope: common.String("nsx-op/version"), + Tag: common.String("1.0.0"), + }, + { + Scope: common.String("nsx-op/vm_namespace"), + Tag: common.String("fake_ns"), + }, + { + Scope: common.String("nsx-op/subnetport_name"), + Tag: common.String(crName), + }, + { + Scope: common.String("nsx-op/subnetport_uid"), + Tag: common.String(crUUID), + }, + }, + Path: common.String("/orgs/default/projects/default/vpcs/vpc1/subnets/subnet1/ports/ports/fake_subnetport-2ccec3b9-7546-4fd2-812a-1e3a4afd7acc"), + ParentPath: common.String("/orgs/default/projects/default/vpcs/vpc1/subnets/subnet1"), + Attachment: &model.PortAttachment{ + AllocateAddresses: common.String("DHCP"), + Type_: common.String("STATIC"), + Id: common.String("66616b65-5f73-4562-ae65-74706f72742d"), + TrafficTag: common.Int64(0), + }, + } + subnetPortService.SubnetPortStore.Add(subnetPortByCR) + subnetPortIDs := subnetPortService.ListNSXSubnetPortIDForCR() + assert.Equal(t, 1, len(subnetPortIDs)) + assert.Equal(t, *subnetPortByCR.Id, subnetPortIDs.UnsortedList()[0]) +} + +func TestListNSXSubnetPortIDForPod(t *testing.T) { + subnetPortService := createSubnetPortService() + podName := "fake_pod" + podUUID := "c5db1800-ce4c-11de-a935-8105ba7ace78" + subnetPortByPod := &model.VpcSubnetPort{ + DisplayName: common.String(podName), + Id: common.String(fmt.Sprintf("fake_pod-%s", podUUID)), + Tags: []model.Tag{ + { + Scope: common.String("nsx-op/cluster"), + Tag: common.String("fake_cluster"), + }, + { + Scope: common.String("nsx-op/version"), + Tag: common.String("1.0.0"), + }, + { + Scope: common.String("nsx-op/namespace"), + Tag: common.String("fake_ns"), + }, + { + Scope: common.String("nsx-op/pod_name"), + Tag: common.String(podName), + }, + { + Scope: common.String("nsx-op/pod_uid"), + Tag: common.String(podUUID), + }, + }, + Path: common.String("/orgs/default/projects/default/vpcs/vpc1/subnets/subnet1/ports/fake_pod-c5db1800-ce4c-11de-a935-8105ba7ace78"), + ParentPath: common.String("/orgs/default/projects/default/vpcs/vpc1/subnets/subnet1"), + Attachment: &model.PortAttachment{ + AllocateAddresses: common.String("DHCP"), + Type_: common.String("STATIC"), + Id: common.String("66616b65-5f70-4f64-ad63-356462313830"), + TrafficTag: common.Int64(0), + AppId: common.String(podUUID), + ContextId: common.String("fake_context_id"), + }, + } + subnetPortService.SubnetPortStore.Add(subnetPortByPod) + subnetPortIDs := subnetPortService.ListNSXSubnetPortIDForPod() + assert.Equal(t, 1, len(subnetPortIDs)) + assert.Equal(t, *subnetPortByPod.Id, subnetPortIDs.UnsortedList()[0]) +} + +func createSubnetPortService() *SubnetPortService { + return &SubnetPortService{ + SubnetPortStore: &SubnetPortStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer( + keyFunc, + cache.Indexers{ + common.TagScopeSubnetPortCRUID: subnetPortIndexByCRUID, + common.TagScopePodUID: subnetPortIndexByPodUID, + common.IndexKeySubnetID: subnetPortIndexBySubnetID, + }), + BindingType: model.VpcSubnetPortBindingType(), + }}, + } +} diff --git a/pkg/nsx/services/vpc/builder.go b/pkg/nsx/services/vpc/builder.go index 1d777f6ea..049bf28fe 100644 --- a/pkg/nsx/services/vpc/builder.go +++ b/pkg/nsx/services/vpc/builder.go @@ -1,11 +1,10 @@ package vpc import ( - "net/netip" - "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + v1 "k8s.io/api/core/v1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) @@ -19,37 +18,18 @@ var ( // using cidr_vpccruid as key so that it could quickly check if ipblocks already created. func generateIPBlockKey(block model.IpAddressBlock) string { cidr := block.Cidr - vpc_uid := "" + nsUID := "" for _, tag := range block.Tags { - if *tag.Scope == common.TagScopeVPCCRUID { - vpc_uid = *tag.Tag + if *tag.Scope == common.TagScopeNamespaceUID { + nsUID = *tag.Tag } } - return *cidr + "_" + vpc_uid -} - -func generateIPBlockSearchKey(cidr string, vpcCRUID string) string { - return cidr + "_" + vpcCRUID + return *cidr + "_" + nsUID } -func buildPrivateIpBlock(vpc *v1alpha1.VPC, cidr, ip, project, cluster string) model.IpAddressBlock { - suffix := vpc.GetNamespace() + "-" + vpc.Name + "-" + ip - addr, _ := netip.ParseAddr(ip) - ipType := util.If(addr.Is4(), model.IpAddressBlock_IP_ADDRESS_TYPE_IPV4, model.IpAddressBlock_IP_ADDRESS_TYPE_IPV6).(string) - blockType := model.IpAddressBlock_VISIBILITY_PRIVATE - block := model.IpAddressBlock{ - DisplayName: common.String(util.GenerateDisplayName("ipblock", "", suffix, "", cluster)), - Id: common.String(string(vpc.UID) + "_" + ip), - Tags: util.BuildBasicTags(cluster, vpc, ""), // ipblock and vpc can use the same tags - Cidr: &cidr, - IpAddressType: &ipType, - Visibility: &blockType, - } - - return block -} - -func buildNSXVPC(obj *v1alpha1.VPC, nc common.VPCNetworkConfigInfo, cluster string, pathMap map[string]string, nsxVPC *model.Vpc) (*model.Vpc, error) { +func buildNSXVPC(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, nc common.VPCNetworkConfigInfo, cluster string, + nsxVPC *model.Vpc, useAVILB bool) (*model.Vpc, + error) { vpc := &model.Vpc{} if nsxVPC != nil { // for upgrade case, only check public/private ip block size changing @@ -58,31 +38,45 @@ func buildNSXVPC(obj *v1alpha1.VPC, nc common.VPCNetworkConfigInfo, cluster stri return nil, nil } // for updating vpc case, use current vpc id, name - vpc = nsxVPC + *vpc = *nsxVPC } else { // for creating vpc case, fill in vpc properties based on networkconfig - vpcName := util.GenerateDisplayName(obj.Name, obj.GetNamespace(), cluster, "", "") + vpcName := util.GenerateIDByObjectByLimit(obj, common.MaxNameLength) vpc.DisplayName = &vpcName - vpc.Id = common.String(string(obj.GetUID())) - vpc.DefaultGatewayPath = &nc.DefaultGatewayPath + vpc.Id = common.String(util.GenerateIDByObject(obj)) vpc.IpAddressType = &DefaultVPCIPAddressType - siteInfos := []model.SiteInfo{ - { - EdgeClusterPaths: []string{nc.EdgeClusterPath}, - }, + if useAVILB { + loadBalancerVPCEndpointEnabled := true + vpc.LoadBalancerVpcEndpoint = &model.LoadBalancerVPCEndpoint{Enabled: &loadBalancerVPCEndpointEnabled} } - vpc.SiteInfos = siteInfos - vpc.LoadBalancerVpcEndpoint = &model.LoadBalancerVPCEndpoint{Enabled: &DefaultLoadBalancerVPCEndpointEnabled} - vpc.Tags = util.BuildBasicTags(cluster, obj, "") + vpc.Tags = util.BuildBasicTags(cluster, obj, nsObj.UID) + vpc.Tags = append(vpc.Tags, model.Tag{ + Scope: common.String(common.TagScopeVPCManagedBy), Tag: common.String(common.AutoCreatedVPCTagValue)}) } - // update private/public blocks - vpc.ExternalIpv4Blocks = nc.ExternalIPv4Blocks - vpc.PrivateIpv4Blocks = util.GetMapValues(pathMap) - if nc.ShortID != "" { - vpc.ShortId = &nc.ShortID + if nc.VPCConnectivityProfile != "" { + vpc.VpcConnectivityProfile = &nc.VPCConnectivityProfile } + vpc.PrivateIps = nc.PrivateIPs return vpc, nil } + +func buildNSXLBS(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, cluster, lbsSize, vpcPath string, relaxScaleValidation *bool) (*model.LBService, error) { + lbs := &model.LBService{} + lbsName := util.GenerateIDByObjectByLimit(obj, common.MaxNameLength) + // Use VPC id for auto-created LBS id + lbs.Id = common.String(util.GenerateIDByObject(obj)) + lbs.DisplayName = &lbsName + lbs.Tags = util.BuildBasicTags(cluster, obj, nsObj.GetUID()) + // "created_for" is required by NCP, and "lb_t1_link_ip" is not needed for VPC + lbs.Tags = append(lbs.Tags, model.Tag{ + Scope: common.String(common.TagScopeCreatedFor), + Tag: common.String(common.TagValueSLB), + }) + lbs.Size = &lbsSize + lbs.ConnectivityPath = &vpcPath + lbs.RelaxScaleValidation = relaxScaleValidation + return lbs, nil +} diff --git a/pkg/nsx/services/vpc/builder_test.go b/pkg/nsx/services/vpc/builder_test.go new file mode 100644 index 000000000..b07947f15 --- /dev/null +++ b/pkg/nsx/services/vpc/builder_test.go @@ -0,0 +1,165 @@ +package vpc + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func Test_buildNSXLBS(t *testing.T) { + type args struct { + obj *v1alpha1.NetworkInfo + nsObj *v1.Namespace + cluster string + lbsSize string + vpcPath string + relaxScaleValidation *bool + } + tests := []struct { + name string + args args + want *model.LBService + wantErr assert.ErrorAssertionFunc + }{ + { + name: "1", + args: args{ + obj: &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "ns1", UID: "netinfouid1"}, + VPCs: nil, + }, + nsObj: &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "ns1", UID: "nsuid1"}, + }, + cluster: "cluster1", + lbsSize: model.LBService_SIZE_SMALL, + vpcPath: "/vpc1", + relaxScaleValidation: nil, + }, + want: &model.LBService{ + Id: common.String("ns1-netinfouid1"), + DisplayName: common.String("ns1-netinfouid1"), + Tags: []model.Tag{ + { + Scope: common.String(common.TagScopeCluster), + Tag: common.String("cluster1"), + }, + { + Scope: common.String(common.TagScopeVersion), + Tag: common.String(strings.Join(common.TagValueVersion, ".")), + }, + {Scope: common.String(common.TagScopeNamespace), Tag: common.String("ns1")}, + {Scope: common.String(common.TagScopeNamespaceUID), Tag: common.String("nsuid1")}, + {Scope: common.String(common.TagScopeCreatedFor), Tag: common.String(common.TagValueSLB)}, + }, + Size: common.String(model.LBService_SIZE_SMALL), + ConnectivityPath: common.String("/vpc1"), + RelaxScaleValidation: nil, + }, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := buildNSXLBS(tt.args.obj, tt.args.nsObj, tt.args.cluster, tt.args.lbsSize, tt.args.vpcPath, tt.args.relaxScaleValidation) + if !tt.wantErr(t, err, fmt.Sprintf("buildNSXLBS(%v, %v, %v, %v, %v, %v)", tt.args.obj, tt.args.nsObj, tt.args.cluster, tt.args.lbsSize, tt.args.vpcPath, tt.args.relaxScaleValidation)) { + return + } + assert.Equalf(t, tt.want, got, "buildNSXLBS(%v, %v, %v, %v, %v, %v)", tt.args.obj, tt.args.nsObj, tt.args.cluster, tt.args.lbsSize, tt.args.vpcPath, tt.args.relaxScaleValidation) + }) + } +} + +func TestBuildNSXVPC(t *testing.T) { + nc := common.VPCNetworkConfigInfo{ + PrivateIPs: []string{"192.168.1.0/24"}, + } + netInfoObj := &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "ns1", UID: "netinfouid1"}, + VPCs: nil, + } + nsObj := &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "ns1", UID: "nsuid1"}, + } + clusterStr := "cluster1" + + for _, tc := range []struct { + name string + existingVPC *model.Vpc + ncPrivateIps []string + useAVILB bool + expVPC *model.Vpc + }{ + { + name: "existing VPC not change", + ncPrivateIps: []string{"192.168.1.0/24"}, + existingVPC: &model.Vpc{ + PrivateIps: []string{"192.168.1.0/24"}, + }, + useAVILB: true, + }, + { + name: "existing VPC changes private IPv4 blocks", + existingVPC: &model.Vpc{ + PrivateIps: []string{}, + }, + ncPrivateIps: []string{"192.168.3.0/24"}, + useAVILB: false, + expVPC: &model.Vpc{ + PrivateIps: []string{"192.168.3.0/24"}, + }, + }, + { + name: "create new VPC with AVI load balancer enabled", + ncPrivateIps: []string{"192.168.3.0/24"}, + useAVILB: true, + expVPC: &model.Vpc{ + Id: common.String("ns1-netinfouid1"), + DisplayName: common.String("ns1-netinfouid1"), + LoadBalancerVpcEndpoint: &model.LoadBalancerVPCEndpoint{Enabled: common.Bool(true)}, + PrivateIps: []string{"192.168.3.0/24"}, + IpAddressType: common.String("IPV4"), + Tags: []model.Tag{ + {Scope: common.String("nsx-op/cluster"), Tag: common.String("cluster1")}, + {Scope: common.String("nsx-op/version"), Tag: common.String("1.0.0")}, + {Scope: common.String("nsx-op/namespace"), Tag: common.String("ns1")}, + {Scope: common.String("nsx-op/namespace_uid"), Tag: common.String("nsuid1")}, + {Scope: common.String("nsx/managed-by"), Tag: common.String("nsx-op")}, + }, + }, + }, + { + name: "create new VPC with AVI load balancer disabled", + ncPrivateIps: []string{"192.168.3.0/24"}, + useAVILB: false, + expVPC: &model.Vpc{ + Id: common.String("ns1-netinfouid1"), + DisplayName: common.String("ns1-netinfouid1"), + PrivateIps: []string{"192.168.3.0/24"}, + IpAddressType: common.String("IPV4"), + Tags: []model.Tag{ + {Scope: common.String("nsx-op/cluster"), Tag: common.String("cluster1")}, + {Scope: common.String("nsx-op/version"), Tag: common.String("1.0.0")}, + {Scope: common.String("nsx-op/namespace"), Tag: common.String("ns1")}, + {Scope: common.String("nsx-op/namespace_uid"), Tag: common.String("nsuid1")}, + {Scope: common.String("nsx/managed-by"), Tag: common.String("nsx-op")}, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + nc.PrivateIPs = tc.ncPrivateIps + got, err := buildNSXVPC(netInfoObj, nsObj, nc, clusterStr, tc.existingVPC, tc.useAVILB) + assert.Nil(t, err) + assert.Equal(t, tc.expVPC, got) + }) + } +} diff --git a/pkg/nsx/services/vpc/clean_avi.go b/pkg/nsx/services/vpc/clean_avi.go new file mode 100644 index 000000000..b5d2108c8 --- /dev/null +++ b/pkg/nsx/services/vpc/clean_avi.go @@ -0,0 +1,61 @@ +package vpc + +import ( + "context" + "errors" + "fmt" + + mapset "github.com/deckarep/golang-set" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" +) + +type ( + mapInterface = map[string]interface{} +) + +const ( + PolicyAPI = "policy/api/v1" +) + +var AviSubnetPortsPathSuffix = fmt.Sprintf("/subnets/%s/ports/", common.AVISubnetLBID) + +func httpGetAviPortsPaths(cluster *nsx.Cluster, vpcPath string) (mapset.Set, error) { + aviSubnetPortsPath := vpcPath + AviSubnetPortsPathSuffix + url := PolicyAPI + aviSubnetPortsPath + + resp, err := cluster.HttpGet(url) + if err != nil { + return nil, err + } + aviPathSet := mapset.NewSet() + for _, item := range resp["results"].([]interface{}) { + aviPathSet.Add(item.(mapInterface)["path"].(string)) + } + return aviPathSet, nil +} + +func CleanAviSubnetPorts(ctx context.Context, cluster *nsx.Cluster, vpcPath string) error { + log.Info("Deleting Avi subnetports started") + + allPaths, err := httpGetAviPortsPaths(cluster, vpcPath) + if err != nil { + return err + } + + log.Info("Deleting Avi subnetport", "paths", allPaths) + for _, path := range allPaths.ToSlice() { + url := PolicyAPI + path.(string) + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + if err := cluster.HttpDelete(url); err != nil { + return err + } + } + } + return nil +} diff --git a/pkg/nsx/services/vpc/compare.go b/pkg/nsx/services/vpc/compare.go index f41ccb66c..45686a7bd 100644 --- a/pkg/nsx/services/vpc/compare.go +++ b/pkg/nsx/services/vpc/compare.go @@ -9,11 +9,7 @@ import ( // currently we only support appending public/private cidrs // so only comparing list size is enough to identify if vcp changed func IsVPCChanged(nc common.VPCNetworkConfigInfo, vpc *model.Vpc) bool { - if len(nc.ExternalIPv4Blocks) != len(vpc.ExternalIpv4Blocks) { - return true - } - - if len(nc.PrivateIPv4CIDRs) != len(vpc.PrivateIpv4Blocks) { + if len(nc.PrivateIPs) != len(vpc.PrivateIps) { return true } diff --git a/pkg/nsx/services/vpc/store.go b/pkg/nsx/services/vpc/store.go index 72115dd0d..001cfe4ab 100644 --- a/pkg/nsx/services/vpc/store.go +++ b/pkg/nsx/services/vpc/store.go @@ -13,6 +13,8 @@ func keyFunc(obj interface{}) (string, error) { switch v := obj.(type) { case *model.Vpc: return *v.Id, nil + case *model.LBService: + return *v.Id, nil case *model.IpAddressBlock: return generateIPBlockKey(*v), nil default: @@ -27,6 +29,8 @@ func indexFunc(obj interface{}) ([]string, error) { switch o := obj.(type) { case *model.Vpc: return filterTag(o.Tags), nil + case *model.LBService: + return filterTag(o.Tags), nil case *model.IpAddressBlock: return filterTag(o.Tags), nil default: @@ -49,7 +53,7 @@ func indexPathFunc(obj interface{}) ([]string, error) { var filterTag = func(v []model.Tag) []string { res := make([]string, 0, 5) for _, tag := range v { - if *tag.Scope == common.TagScopeVPCCRUID { + if *tag.Scope == common.TagScopeNamespaceUID { res = append(res, *tag.Tag) } } @@ -137,6 +141,15 @@ func (vs *VPCStore) GetByKey(key string) *model.Vpc { return nil } +// ResourceStore is a store to query nsx resource +type ResourceStore struct { + common.ResourceStore +} + +func (r *ResourceStore) Apply(i interface{}) error { + return nil +} + func (is *IPBlockStore) GetByIndex(index string, value string) *model.IpAddressBlock { indexResults, err := is.ResourceStore.Indexer.ByIndex(index, value) if err != nil || len(indexResults) == 0 { @@ -148,85 +161,37 @@ func (is *IPBlockStore) GetByIndex(index string, value string) *model.IpAddressB return block } -// keyFuncAVI is used to get the key of a AVI rule related resource -func keyFuncAVI(obj interface{}) (string, error) { - switch v := obj.(type) { - case *model.Rule: - return *v.Path, nil - case *model.SecurityPolicy: - return *v.Path, nil - case *model.Group: - return *v.Path, nil - case *model.IpAddressBlock: - return *v.Path, nil - default: - return "", errors.New("keyFunc doesn't support unknown type") - } -} - -// AviRuleStore is a store for saving AVI related Rules in VPCs -type AviRuleStore struct { +// LBSStore is a store for LBS +type LBSStore struct { common.ResourceStore } -func (ruleStore *AviRuleStore) Apply(i interface{}) error { - return nil -} -func (ruleStore *AviRuleStore) GetByKey(key string) *model.Rule { - obj := ruleStore.ResourceStore.GetByKey(key) - if obj != nil { - rule := obj.(*model.Rule) - return rule - } - return nil -} - -// PubIPblockStore is a store to query external ip blocks cidr -type PubIPblockStore struct { - common.ResourceStore -} - -func (ipBlockStore *PubIPblockStore) Apply(i interface{}) error { - return nil -} -func (ipBlockStore *PubIPblockStore) GetByKey(key string) *model.IpAddressBlock { - obj := ipBlockStore.ResourceStore.GetByKey(key) - if obj != nil { - ipblock := obj.(*model.IpAddressBlock) - return ipblock +func (ls *LBSStore) Apply(i interface{}) error { + if i == nil { + return nil } - return nil -} - -type AviGroupStore struct { - common.ResourceStore -} - -func (groupStore *AviGroupStore) Apply(i interface{}) error { - return nil -} -func (groupStore *AviGroupStore) GetByKey(key string) *model.Group { - obj := groupStore.ResourceStore.GetByKey(key) - if obj != nil { - group := obj.(*model.Group) - return group + lbs := i.(*model.LBService) + if lbs.MarkedForDelete != nil && *lbs.MarkedForDelete { + err := ls.Delete(lbs) + log.V(1).Info("delete LBS from store", "LBS", lbs) + if err != nil { + return err + } + } else { + err := ls.Add(lbs) + log.V(1).Info("add LBS to store", "LBS", lbs) + if err != nil { + return err + } } return nil } -type AviSecurityPolicyStore struct { - common.ResourceStore -} - -func (securityPolicyStore *AviSecurityPolicyStore) Apply(i interface{}) error { - return nil -} - -func (securityPolicyStore *AviSecurityPolicyStore) GetByKey(key string) *model.SecurityPolicy { - obj := securityPolicyStore.ResourceStore.GetByKey(key) +func (ls *LBSStore) GetByKey(key string) *model.LBService { + obj := ls.ResourceStore.GetByKey(key) if obj != nil { - sp := obj.(*model.SecurityPolicy) - return sp + lbs := obj.(*model.LBService) + return lbs } return nil } diff --git a/pkg/nsx/services/vpc/store_test.go b/pkg/nsx/services/vpc/store_test.go index 22b09104c..477273758 100644 --- a/pkg/nsx/services/vpc/store_test.go +++ b/pkg/nsx/services/vpc/store_test.go @@ -8,6 +8,7 @@ import ( "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" "github.com/vmware/vsphere-automation-sdk-go/runtime/data" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" @@ -32,22 +33,8 @@ func (qIface *fakeQueryClient) List(_ string, _ *string, _ *string, _ *int64, _ }, nil } -func Test_IndexFunc(t *testing.T) { - mId, mTag, mScope := "test_id", "test_tag", "nsx-op/vpc_uid" - v := &model.Vpc{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - t.Run("1", func(t *testing.T) { - got, _ := indexFunc(v) - if !reflect.DeepEqual(got, []string{"test_tag"}) { - t.Errorf("VPCCRUIDScopeIndexFunc() = %v, want %v", got, model.Tag{Tag: &mTag, Scope: &mScope}) - } - }) -} - func Test_filterTag(t *testing.T) { - mTag, mScope := "test_tag", "nsx-op/vpc_uid" + mTag, mScope := "test_tag", "nsx-op/namespace_uid" mTag2, mScope2 := "test_tag", "nsx" tags := []model.Tag{{Scope: &mScope, Tag: &mTag}} tags2 := []model.Tag{{Scope: &mScope2, Tag: &mTag2}} @@ -74,22 +61,11 @@ func Test_filterTag(t *testing.T) { } } -func Test_KeyFunc(t *testing.T) { - Id := "test_id" - v := &model.Vpc{Id: &Id} - t.Run("1", func(t *testing.T) { - got, _ := keyFunc(v) - if got != "test_id" { - t.Errorf("keyFunc() = %v, want %v", got, "test_id") - } - }) -} - func Test_InitializeVPCStore(t *testing.T) { config2 := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) cluster, _ := nsx.NewCluster(config2) rc, _ := cluster.NewRestConnector() - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) + vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{}) vpcStore := &VPCStore{ResourceStore: common.ResourceStore{ Indexer: vpcCacheIndexer, BindingType: model.VpcBindingType(), @@ -134,11 +110,11 @@ func Test_InitializeVPCStore(t *testing.T) { service.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeVpc, nil, vpcStore) assert.Empty(t, fatalErrors) - assert.Equal(t, sets.New[string](), vpcStore.ListIndexFuncValues(common.TagScopeVPCCRUID)) + assert.Equal(t, sets.New[string](), vpcStore.ListIndexFuncValues(common.TagScopeNamespaceUID)) } func TestVPCStore_CRUDResource(t *testing.T) { - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) + vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{}) resourceStore := common.ResourceStore{ Indexer: vpcCacheIndexer, BindingType: model.VpcBindingType(), @@ -162,7 +138,7 @@ func TestVPCStore_CRUDResource(t *testing.T) { } func TestVPCStore_CRUDResource_List(t *testing.T) { - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) + vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{}) resourceStore := common.ResourceStore{ Indexer: vpcCacheIndexer, BindingType: model.VpcBindingType(), @@ -182,14 +158,6 @@ func TestVPCStore_CRUDResource_List(t *testing.T) { Scope: &tagScopeNamespace, Tag: &ns1, }, - { - Scope: &tagScopeVPCCRName, - Tag: &tagValueVPCCRName, - }, - { - Scope: &tagScopeVPCCRUID, - Tag: &tagValueVPCCRUID, - }, } ns2 := "test-ns-2" tag2 := []model.Tag{ @@ -201,14 +169,6 @@ func TestVPCStore_CRUDResource_List(t *testing.T) { Scope: &tagScopeNamespace, Tag: &ns2, }, - { - Scope: &tagScopeVPCCRName, - Tag: &tagValueVPCCRName, - }, - { - Scope: &tagScopeVPCCRUID, - Tag: &tagValueVPCCRUID, - }, } vpc1 := model.Vpc{ @@ -255,101 +215,128 @@ func TestVPCStore_CRUDResource_List(t *testing.T) { } } -func TestRuleStore_GetByKey(t *testing.T) { - vpcRuleCacheIndexer := cache.NewIndexer(keyFuncAVI, nil) - resourceStore := common.ResourceStore{ - Indexer: vpcRuleCacheIndexer, - BindingType: model.RuleBindingType(), - } - ruleStore := &AviRuleStore{ResourceStore: resourceStore} - service := &VPCService{ - Service: common.Service{NSXClient: nil}, +func Test_keyFunc(t *testing.T) { + id := "test_id" + type args struct { + obj interface{} } - service.RuleStore = ruleStore - - path1 := "/org/default/project/project_1/vpcs/vpc1/security-policies/default-section/rules/rule1" - path2 := "/org/default/project/project_1/vpcs/vpc2/security-policies/default-section/rules/rule1" - rule1 := model.Rule{ - Path: &path1, + tests := []struct { + name string + args args + want string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "vpc", + args: args{obj: &model.Vpc{Id: &id}}, + want: id, + wantErr: assert.NoError, + }, + { + name: "lbs", + args: args{obj: &model.LBService{Id: &id}}, + want: id, + wantErr: assert.NoError, + }, + { + name: "invalid", + args: args{obj: &model.AntreaTraceflowConfig{Id: &id}}, + want: "", + wantErr: assert.Error, + }, } - rule2 := model.Rule{ - Path: &path2, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := keyFunc(tt.args.obj) + if !tt.wantErr(t, err, fmt.Sprintf("keyFunc(%v)", tt.args.obj)) { + return + } + assert.Equalf(t, tt.want, got, "keyFunc(%v)", tt.args.obj) + }) } - ruleStore.Add(&rule1) - - rule := ruleStore.GetByKey(path1) - assert.Equal(t, rule.Path, rule1.Path) - - rule = ruleStore.GetByKey(path2) - assert.True(t, rule == nil) - - ruleStore.Add(&rule2) - rule = ruleStore.GetByKey(path2) - assert.Equal(t, rule.Path, rule2.Path) } -func TestGroupStore_GetByKey(t *testing.T) { - groupCacheIndexer := cache.NewIndexer(keyFuncAVI, nil) - resourceStore := common.ResourceStore{ - Indexer: groupCacheIndexer, - BindingType: model.GroupBindingType(), - } - groupStore := &AviGroupStore{ResourceStore: resourceStore} - service := &VPCService{ - Service: common.Service{NSXClient: nil}, +func Test_indexFunc(t *testing.T) { + mId, mTag, mScope := "test_id", "test_tag", "nsx-op/namespace_uid" + type args struct { + obj interface{} } - service.GroupStore = groupStore - - path1 := "/org/default/project/project_1/vpcs/vpc1/groups/group1" - path2 := "/org/default/project/project_1/vpcs/vpc2/groups/group2" - group1 := model.Group{ - Path: &path1, + tests := []struct { + name string + args args + want []string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "vpc", + args: args{obj: &model.Vpc{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + }}, + want: []string{"test_tag"}, + wantErr: assert.NoError, + }, + { + name: "lbs", + args: args{obj: &model.LBService{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + }}, + want: []string{"test_tag"}, + wantErr: assert.NoError, + }, + { + name: "lbsnotag", + args: args{obj: &model.LBService{ + Id: &mId, + Tags: []model.Tag{}, + }}, + want: []string{}, + wantErr: assert.NoError, + }, + { + name: "invalid", + args: args{obj: &model.AntreaTraceflowConfig{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + }}, + want: []string{}, + wantErr: assert.Error, + }, } - group2 := model.Group{ - Path: &path2, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := indexFunc(tt.args.obj) + if !tt.wantErr(t, err, fmt.Sprintf("indexFunc(%v)", tt.args.obj)) { + return + } + assert.Equalf(t, tt.want, got, "indexFunc(%v)", tt.args.obj) + }) } - groupStore.Add(&group1) - - group := groupStore.GetByKey(path1) - assert.Equal(t, group.Path, group1.Path) - - group = groupStore.GetByKey(path2) - assert.True(t, group == nil) - - groupStore.Add(&group2) - group = groupStore.GetByKey(path2) - assert.Equal(t, group.Path, group2.Path) } -func TestSecurityPolicyStore_GetByKey(t *testing.T) { - spCacheIndexer := cache.NewIndexer(keyFuncAVI, nil) +func TestLBSStore_CRUD(t *testing.T) { + vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{}) resourceStore := common.ResourceStore{ - Indexer: spCacheIndexer, - BindingType: model.SecurityPolicyBindingType(), - } - spStore := &AviSecurityPolicyStore{ResourceStore: resourceStore} - service := &VPCService{ - Service: common.Service{NSXClient: nil}, - } - service.SecurityPolicyStore = spStore - - path1 := "/org/default/project/project_1/vpcs/vpc1/security-policies/default-section" - path2 := "/org/default/project/project_1/vpcs/vpc2/security-policies/default-section" - sp1 := model.SecurityPolicy{ - Path: &path1, + Indexer: vpcCacheIndexer, + BindingType: model.LBServiceBindingType(), } - sp2 := model.SecurityPolicy{ - Path: &path2, + ls := &LBSStore{ + ResourceStore: resourceStore, } - spStore.Add(&sp1) - - sp := spStore.GetByKey(path1) - assert.Equal(t, sp.Path, sp1.Path) - - sp = spStore.GetByKey(path2) - assert.True(t, sp == nil) - - spStore.Add(&sp2) - sp = spStore.GetByKey(path2) - assert.Equal(t, sp.Path, sp2.Path) + lbs1 := &model.LBService{Id: common.String("1")} + lbs2 := &model.LBService{Id: common.String("2")} + require.NoError(t, ls.Apply(lbs1)) + require.Equal(t, 1, len(ls.List())) + require.True(t, reflect.DeepEqual(lbs1, ls.GetByKey("1"))) + require.NoError(t, ls.Apply(lbs2)) + require.Equal(t, 2, len(ls.List())) + lbs2.MarkedForDelete = common.Bool(true) + require.NoError(t, ls.Apply(lbs2)) + require.Equal(t, 1, len(ls.List())) + require.Nil(t, ls.GetByKey("2")) + defer func() { + require.NotNil(t, recover()) + }() + ls.Apply(&model.AntreaTraceflowConfig{Id: common.String("invalid")}) } diff --git a/pkg/nsx/services/vpc/vpc.go b/pkg/nsx/services/vpc/vpc.go index 7486551a3..7421fc055 100644 --- a/pkg/nsx/services/vpc/vpc.go +++ b/pkg/nsx/services/vpc/vpc.go @@ -4,20 +4,16 @@ import ( "context" "errors" "fmt" - "math" - "net" "strings" "sync" - "github.com/vmware/vsphere-automation-sdk-go/runtime/data" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/retry" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" @@ -27,38 +23,45 @@ import ( ) const ( - AviSEIngressAllowRuleId = "avi-se-ingress-allow-rule" - VPCAviSEGroupId = "avi-se-vms" VpcDefaultSecurityPolicyId = "default-layer3-section" + VPCKey = "/orgs/%s/projects/%s/vpcs/%s" GroupKey = "/orgs/%s/projects/%s/vpcs/%s/groups/%s" SecurityPolicyKey = "/orgs/%s/projects/%s/vpcs/%s/security-policies/%s" RuleKey = "/orgs/%s/projects/%s/vpcs/%s/security-policies/%s/rules/%s" + albEndpointPath = "policy/api/v1/infra/sites/default/enforcement-points/alb-endpoint" + LBProviderNSX = "nsx-lb" + LBProviderAVI = "avi" ) var ( - log = logger.Log - ctx = context.Background() - ResourceTypeVPC = common.ResourceTypeVpc - NewConverter = common.NewConverter - - MarkedForDelete = true - enableAviAllowRule = false + log = &logger.Log + ctx = context.Background() + ResourceTypeVPC = common.ResourceTypeVpc + NewConverter = common.NewConverter + lbProvider = "" + lbProviderMutex = &sync.Mutex{} + MarkedForDelete = true + EnforceRevisionCheckParam = false ) +type VPCNetworkInfoStore struct { + sync.RWMutex + VPCNetworkConfigMap map[string]common.VPCNetworkConfigInfo +} + +type VPCNsNetworkConfigStore struct { + sync.Mutex + VPCNSNetworkConfigMap map[string]string +} + type VPCService struct { common.Service - VpcStore *VPCStore - IpblockStore *IPBlockStore - VPCNetworkConfigMap map[string]common.VPCNetworkConfigInfo - VPCNSNetworkConfigMap map[string]string - defaultNetworkConfigCR *common.VPCNetworkConfigInfo - AVIAllowRule -} -type AVIAllowRule struct { - GroupStore *AviGroupStore - RuleStore *AviRuleStore - SecurityPolicyStore *AviSecurityPolicyStore - PubIpblockStore *PubIPblockStore + VpcStore *VPCStore + LbsStore *LBSStore + IpblockStore *IPBlockStore + VPCNetworkConfigStore VPCNetworkInfoStore + VPCNSNetworkConfigStore VPCNsNetworkConfigStore + defaultNetworkConfigCR *common.VPCNetworkConfigInfo } func (s *VPCService) GetDefaultNetworkConfig() (bool, *common.VPCNetworkConfigInfo) { @@ -69,33 +72,41 @@ func (s *VPCService) GetDefaultNetworkConfig() (bool, *common.VPCNetworkConfigIn } func (s *VPCService) RegisterVPCNetworkConfig(ncCRName string, info common.VPCNetworkConfigInfo) { - s.VPCNetworkConfigMap[ncCRName] = info + s.VPCNetworkConfigStore.Lock() + s.VPCNetworkConfigStore.VPCNetworkConfigMap[ncCRName] = info if info.IsDefault { s.defaultNetworkConfigCR = &info } + s.VPCNetworkConfigStore.Unlock() } func (s *VPCService) UnregisterVPCNetworkConfig(ncCRName string) { - delete(s.VPCNetworkConfigMap, ncCRName) + s.VPCNetworkConfigStore.Lock() + delete(s.VPCNetworkConfigStore.VPCNetworkConfigMap, ncCRName) + s.VPCNetworkConfigStore.Unlock() } func (s *VPCService) GetVPCNetworkConfig(ncCRName string) (common.VPCNetworkConfigInfo, bool) { - nc, exist := s.VPCNetworkConfigMap[ncCRName] + nc, exist := s.VPCNetworkConfigStore.VPCNetworkConfigMap[ncCRName] return nc, exist } func (s *VPCService) RegisterNamespaceNetworkconfigBinding(ns string, ncCRName string) { - s.VPCNSNetworkConfigMap[ns] = ncCRName + s.VPCNSNetworkConfigStore.Lock() + s.VPCNSNetworkConfigStore.VPCNSNetworkConfigMap[ns] = ncCRName + s.VPCNSNetworkConfigStore.Unlock() } func (s *VPCService) UnRegisterNamespaceNetworkconfigBinding(ns string) { - delete(s.VPCNSNetworkConfigMap, ns) + s.VPCNSNetworkConfigStore.Lock() + delete(s.VPCNSNetworkConfigStore.VPCNSNetworkConfigMap, ns) + s.VPCNSNetworkConfigStore.Unlock() } // find the namespace list which is using the given network configuration func (s *VPCService) GetNamespacesByNetworkconfigName(nc string) []string { result := []string{} - for key, value := range s.VPCNSNetworkConfigMap { + for key, value := range s.VPCNSNetworkConfigStore.VPCNSNetworkConfigMap { if value == nc { result = append(result, key) } @@ -104,7 +115,7 @@ func (s *VPCService) GetNamespacesByNetworkconfigName(nc string) []string { } func (s *VPCService) GetVPCNetworkConfigByNamespace(ns string) *common.VPCNetworkConfigInfo { - ncName, nameExist := s.VPCNSNetworkConfigMap[ns] + ncName, nameExist := s.VPCNSNetworkConfigStore.VPCNSNetworkConfigMap[ns] if !nameExist { log.Info("failed to get network config name for namespace", "Namespace", ns) return nil @@ -121,7 +132,11 @@ func (s *VPCService) GetVPCNetworkConfigByNamespace(ns string) *common.VPCNetwor // TBD: for now, if network config info do not contains private cidr, we consider this is // incorrect configuration, and skip creating this VPC CR func (s *VPCService) ValidateNetworkConfig(nc common.VPCNetworkConfigInfo) bool { - return nc.PrivateIPv4CIDRs != nil && len(nc.PrivateIPv4CIDRs) != 0 + if IsPreCreatedVPC(nc) { + // if network config is using a pre-created VPC, skip the check on PrivateIPs. + return true + } + return nc.PrivateIPs != nil && len(nc.PrivateIPs) != 0 } // InitializeVPC sync NSX resources @@ -131,56 +146,31 @@ func InitializeVPC(service common.Service) (*VPCService, error) { fatalErrors := make(chan error) VPCService := &VPCService{Service: service} - enableAviAllowRule = service.NSXClient.FeatureEnabled(nsx.VpcAviRule) - if enableAviAllowRule { - log.Info("support avi allow rule") - wg.Add(5) - } else { - log.Info("disable avi allow rule") - wg.Add(2) - } VPCService.VpcStore = &VPCStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}), + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), BindingType: model.VpcBindingType(), }} + VPCService.LbsStore = &LBSStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBServiceBindingType(), + }} VPCService.IpblockStore = &IPBlockStore{ResourceStore: common.ResourceStore{ Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ - common.TagScopeVPCCRUID: indexFunc, common.IndexKeyPathPath: indexPathFunc}), BindingType: model.IpAddressBlockBindingType(), }} - VPCService.VPCNetworkConfigMap = make(map[string]common.VPCNetworkConfigInfo) - VPCService.VPCNSNetworkConfigMap = make(map[string]string) - //initialize vpc store and ip blocks store + VPCService.VPCNetworkConfigStore = VPCNetworkInfoStore{ + VPCNetworkConfigMap: make(map[string]common.VPCNetworkConfigInfo), + } + VPCService.VPCNSNetworkConfigStore = VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: make(map[string]string), + } + // initialize vpc store, lbs store and ip blocks store go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeVpc, nil, VPCService.VpcStore) + go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeLBService, nil, VPCService.LbsStore) go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeIPBlock, nil, VPCService.IpblockStore) - - //initalize avi rule related store - if enableAviAllowRule { - VPCService.RuleStore = &AviRuleStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFuncAVI, nil), - BindingType: model.RuleBindingType(), - }} - VPCService.GroupStore = &AviGroupStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFuncAVI, nil), - BindingType: model.GroupBindingType(), - }} - VPCService.SecurityPolicyStore = &AviSecurityPolicyStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFuncAVI, nil), - BindingType: model.SecurityPolicyBindingType(), - }} - VPCService.PubIpblockStore = &PubIPblockStore{ResourceStore: common.ResourceStore{ - Indexer: cache.NewIndexer(keyFuncAVI, nil), - BindingType: model.IpAddressBlockBindingType(), - }} - go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeGroup, nil, VPCService.GroupStore) - go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeRule, nil, VPCService.RuleStore) - - query := fmt.Sprintf("%s:%s AND visibility:EXTERNAL", common.ResourceType, common.ResourceTypeIPBlock) - go VPCService.PopulateResourcetoStore(&wg, fatalErrors, common.ResourceTypeIPBlock, query, VPCService.PubIpblockStore, nil) - } - + wg.Add(3) go func() { wg.Wait() close(wgDone) @@ -227,8 +217,13 @@ func (s *VPCService) DeleteVPC(path string) error { } if err := vpcClient.Delete(pathInfo.OrgID, pathInfo.ProjectID, pathInfo.VPCID); err != nil { + err = nsxutil.NSXApiError(err) return err } + lbs := s.LbsStore.GetByKey(pathInfo.VPCID) + if lbs != nil { + s.LbsStore.Delete(lbs) + } vpc.MarkedForDelete = &MarkedForDelete if err := s.VpcStore.Apply(vpc); err != nil { return err @@ -238,11 +233,210 @@ func (s *VPCService) DeleteVPC(path string) error { return nil } +func (s *VPCService) addClusterTag(query string) string { + tagScopeClusterKey := strings.Replace(common.TagScopeNCPCluster, "/", "\\/", -1) + tagScopeClusterValue := strings.Replace(s.NSXClient.NsxConfig.Cluster, ":", "\\:", -1) + tagParam := fmt.Sprintf("tags.scope:%s AND tags.tag:%s", tagScopeClusterKey, tagScopeClusterValue) + return query + " AND " + tagParam +} + +func (s *VPCService) ListCert() []model.TlsCertificate { + store := &ResourceStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.TlsCertificateBindingType(), + }} + query := fmt.Sprintf("%s:%s", common.ResourceType, common.ResourceTypeTlsCertificate) + query = s.addClusterTag(query) + count, searcherr := s.SearchResource(common.ResourceTypeTlsCertificate, query, store, nil) + if searcherr != nil { + log.Error(searcherr, "failed to query certificate", "query", query) + } else { + log.V(1).Info("query certificate", "count", count) + } + certs := store.List() + certsSet := []model.TlsCertificate{} + for _, cert := range certs { + certsSet = append(certsSet, *cert.(*model.TlsCertificate)) + } + return certsSet +} + +func (s *VPCService) DeleteCert(id string) error { + certClient := s.NSXClient.CertificateClient + if err := certClient.Delete(id); err != nil { + return err + } + log.Info("successfully deleted NCP created certificate", "certificate", id) + return nil +} + +func (s *VPCService) ListShare() []model.Share { + store := &ResourceStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.ShareBindingType(), + }} + query := fmt.Sprintf("%s:%s", common.ResourceType, common.ResourceTypeShare) + query = s.addClusterTag(query) + count, searcherr := s.SearchResource(common.ResourceTypeShare, query, store, nil) + if searcherr != nil { + log.Error(searcherr, "failed to query share", "query", query) + } else { + log.V(1).Info("query share", "count", count) + } + shares := store.List() + sharesSet := []model.Share{} + for _, cert := range shares { + sharesSet = append(sharesSet, *cert.(*model.Share)) + } + return sharesSet +} + +func (s *VPCService) DeleteShare(shareId string) error { + shareClient := s.NSXClient.ShareClient + if err := shareClient.Delete(shareId); err != nil { + return err + } + log.Info("successfully deleted NCP created share", "share", shareId) + return nil +} + +func (s *VPCService) ListSharedResource() []model.SharedResource { + store := &ResourceStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.SharedResourceBindingType(), + }} + query := fmt.Sprintf("%s:%s", common.ResourceType, common.ResourceTypeSharedResource) + query = s.addClusterTag(query) + count, searcherr := s.SearchResource(common.ResourceTypeSharedResource, query, store, nil) + if searcherr != nil { + log.Error(searcherr, "failed to query sharedResource", "query", query) + } else { + log.V(1).Info("query sharedResource", "count", count) + } + sharedResources := store.List() + sharedResourcesSet := []model.SharedResource{} + for _, sharedResource := range sharedResources { + sharedResourcesSet = append(sharedResourcesSet, *sharedResource.(*model.SharedResource)) + } + return sharedResourcesSet +} + +func (s *VPCService) DeleteSharedResource(shareId, id string) error { + sharedResourceClient := s.NSXClient.SharedResourceClient + if err := sharedResourceClient.Delete(shareId, id); err != nil { + return err + } + log.Info("successfully deleted NCP created sharedResource", "shareId", shareId, "sharedResource", id) + return nil +} + +func (s *VPCService) ListLBAppProfile() []model.LBAppProfile { + store := &ResourceStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBAppProfileBindingType(), + }} + query := fmt.Sprintf("(%s:%s OR %s:%s OR %s:%s)", + common.ResourceType, common.ResourceTypeLBHttpProfile, + common.ResourceType, common.ResourceTypeLBFastTcpProfile, + common.ResourceType, common.ResourceTypeLBFastUdpProfile) + query = s.addClusterTag(query) + count, searcherr := s.SearchResource(common.ResourceTypeLBHttpProfile, query, store, nil) + if searcherr != nil { + log.Error(searcherr, "failed to query LBAppProfile", "query", query) + } else { + log.V(1).Info("query LBAppProfile", "count", count) + } + lbAppProfiles := store.List() + lbAppProfilesSet := []model.LBAppProfile{} + for _, lbAppProfile := range lbAppProfiles { + lbAppProfilesSet = append(lbAppProfilesSet, *lbAppProfile.(*model.LBAppProfile)) + } + return lbAppProfilesSet +} + +func (s *VPCService) DeleteLBAppProfile(id string) error { + lbAppProfileClient := s.NSXClient.LbAppProfileClient + boolValue := false + if err := lbAppProfileClient.Delete(id, &boolValue); err != nil { + return err + } + log.Info("successfully deleted NCP created lbAppProfile", "lbAppProfile", id) + return nil +} + +func (s *VPCService) ListLBPersistenceProfile() []model.LBPersistenceProfile { + store := &ResourceStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBPersistenceProfileBindingType(), + }} + query := fmt.Sprintf("(%s:%s OR %s:%s)", + common.ResourceType, common.ResourceTypeLBCookiePersistenceProfile, + common.ResourceType, common.ResourceTypeLBSourceIpPersistenceProfile) + query = s.addClusterTag(query) + count, searcherr := s.SearchResource("", query, store, nil) + if searcherr != nil { + log.Error(searcherr, "failed to query LBPersistenceProfile", "query", query) + } else { + log.V(1).Info("query LBPersistenceProfile", "count", count) + } + lbPersistenceProfiles := store.List() + lbPersistenceProfilesSet := []model.LBPersistenceProfile{} + for _, lbPersistenceProfile := range lbPersistenceProfiles { + lbPersistenceProfilesSet = append(lbPersistenceProfilesSet, *lbPersistenceProfile.(*model.LBPersistenceProfile)) + } + return lbPersistenceProfilesSet +} + +func (s *VPCService) DeleteLBPersistenceProfile(id string) error { + lbPersistenceProfilesClient := s.NSXClient.LbPersistenceProfilesClient + boolValue := false + if err := lbPersistenceProfilesClient.Delete(id, &boolValue); err != nil { + return err + } + log.Info("successfully deleted NCP created lbPersistenceProfile", "lbPersistenceProfile", id) + return nil +} + +func (s *VPCService) ListLBMonitorProfile() []model.LBMonitorProfile { + store := &ResourceStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBMonitorProfileBindingType(), + }} + query := fmt.Sprintf("(%s:%s OR %s:%s)", + common.ResourceType, common.ResourceTypeLBHttpMonitorProfile, + common.ResourceType, common.ResourceTypeLBTcpMonitorProfile) + query = s.addClusterTag(query) + count, searcherr := s.SearchResource("", query, store, nil) + if searcherr != nil { + log.Error(searcherr, "failed to query LBMonitorProfile", "query", query) + } else { + log.V(1).Info("query LBMonitorProfile", "count", count) + } + lbMonitorProfiles := store.List() + lbMonitorProfilesSet := []model.LBMonitorProfile{} + for _, lbMonitorProfile := range lbMonitorProfiles { + lbMonitorProfilesSet = append(lbMonitorProfilesSet, *lbMonitorProfile.(*model.LBMonitorProfile)) + } + return lbMonitorProfilesSet +} + +func (s *VPCService) DeleteLBMonitorProfile(id string) error { + lbMonitorProfilesClient := s.NSXClient.LbMonitorProfilesClient + boolValue := false + //nolint:staticcheck // SA1019 ignore this! + if err := lbMonitorProfilesClient.Delete(id, &boolValue); err != nil { + return err + } + log.Info("successfully deleted NCP created lbMonitorProfile", "lbMonitorProfile", id) + return nil +} + func (s *VPCService) deleteIPBlock(path string) error { ipblockClient := s.NSXClient.IPBlockClient parts := strings.Split(path, "/") log.Info("deleting private ip block", "ORG", parts[2], "Project", parts[4], "ID", parts[7]) if err := ipblockClient.Delete(parts[2], parts[4], parts[7]); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete ip block", "Path", path) return err } @@ -260,13 +454,13 @@ func (s *VPCService) DeleteIPBlockInVPC(vpc model.Vpc) error { if err := s.deleteIPBlock(block); err != nil { return err } - vpcCRUid := "" + nsUID := "" for _, tag := range vpc.Tags { - if *tag.Scope == common.TagScopeVPCCRUID { - vpcCRUid = *tag.Tag + if *tag.Scope == common.TagScopeNamespaceUID { + nsUID = *tag.Tag } } - log.V(2).Info("search ip block from store using index and path", "index", common.TagScopeVPCCRUID, "Value", vpcCRUid, "Path", block) + log.V(2).Info("search ip block from store using index and path", "index", common.TagScopeNamespaceUID, "Value", nsUID, "Path", block) // using index vpc cr id may get multiple ipblocks, add path to filter the correct one ipblock := s.IpblockStore.GetByIndex(common.IndexKeyPathPath, block) if ipblock != nil { @@ -279,55 +473,18 @@ func (s *VPCService) DeleteIPBlockInVPC(vpc model.Vpc) error { return nil } -func (s *VPCService) CreatOrUpdatePrivateIPBlock(obj *v1alpha1.VPC, nc common.VPCNetworkConfigInfo) (map[string]string, error) { - // if network config contains PrivateIPV4CIDRs section, create private ip block for each cidr - path := map[string]string{} - if nc.PrivateIPv4CIDRs != nil { - for _, pCidr := range nc.PrivateIPv4CIDRs { - log.Info("start processing private cidr", "cidr", pCidr) - // if parse success, then check if private cidr exist, here we suppose it must be a cidr format string - ip, _, err := net.ParseCIDR(pCidr) - if err != nil { - message := fmt.Sprintf("invalid cidr %s for VPC %s", pCidr, obj.Name) - fmtError := errors.New(message) - log.Error(fmtError, message) - return nil, fmtError - } - // check if private ip block already exist - // use cidr_project_ns as search key - key := generateIPBlockSearchKey(pCidr, string(obj.UID)) - log.Info("using key to search from ipblock store", "Key", key) - block := s.IpblockStore.GetByKey(key) - if block == nil { - log.Info("no ip block found in store for cidr", "CIDR", pCidr) - block := buildPrivateIpBlock(obj, pCidr, ip.String(), nc.NsxtProject, s.NSXConfig.Cluster) - log.Info("creating ip block", "IPBlock", block.Id, "VPC", obj.Name) - // can not find private ip block from store, create one - _err := s.NSXClient.IPBlockClient.Patch(nc.Org, nc.NsxtProject, *block.Id, block) - if _err != nil { - message := fmt.Sprintf("failed to create private ip block for cidr %s for VPC %s", pCidr, obj.Name) - ipblockError := errors.New(message) - log.Error(ipblockError, message) - return nil, ipblockError - } - ignoreIpblockUsage := true - createdBlock, err := s.NSXClient.IPBlockClient.Get(nc.Org, nc.NsxtProject, *block.Id, &ignoreIpblockUsage) - if err != nil { - // created by can not get, ignore this error - log.Info("failed to read ip blocks from NSX", "Project", nc.NsxtProject, "IPBlock", block.Id) - continue - } - // update ip block store - s.IpblockStore.Add(&createdBlock) - path[pCidr] = *createdBlock.Path - } else { - eBlock := block.(*model.IpAddressBlock) - path[pCidr] = *eBlock.Path - log.Info("ip block found in store for cidr using key", "CIDR", pCidr, "Key", key) - } - } +func (s *VPCService) IsSharedVPCNamespaceByNS(ns string) (bool, error) { + shared_ns, err := s.getSharedVPCNamespaceFromNS(ns) + if err != nil { + return false, err + } + if shared_ns == "" { + return false, nil + } + if shared_ns != ns { + return true, nil } - return path, nil + return false, err } func (s *VPCService) getSharedVPCNamespaceFromNS(ns string) (string, error) { @@ -346,19 +503,15 @@ func (s *VPCService) getSharedVPCNamespaceFromNS(ns string) (string, error) { return "", nil } - // If no annotation nsx.vmware.com/vpc_name on ns, this is not a shared vpc - ncName, exist := annos[common.AnnotationVPCName] + // If no annotation nsx.vmware.com/shared_vpc_namespace on ns, this is not a shared vpc + shared_ns, exist := annos[common.AnnotationSharedVPCNamespace] if !exist { return "", nil } - - // Retrieve the shared vpc namespace from annotation - shared_ns := strings.Split(ncName, "/")[0] - return shared_ns, nil } -func (s *VPCService) getNetworkconfigNameFromNS(ns string) (string, error) { +func (s *VPCService) GetNetworkconfigNameFromNS(ns string) (string, error) { obj := &v1.Namespace{} if err := s.Client.Get(ctx, types.NamespacedName{ Name: ns, @@ -404,6 +557,7 @@ func (s *VPCService) GetDefaultSNATIP(vpc model.Vpc) (string, error) { pageSize := int64(1000) markedForDelete := false results, err := ruleClient.List(info.OrgID, info.ProjectID, info.VPCID, common.DefaultSNATID, cursor, &markedForDelete, nil, &pageSize, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to read SNAT rule list to get default SNAT ip", "VPC", vpc.Id) return "", err @@ -429,6 +583,7 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) { } subnet, err := subnetsClient.Get(info.OrgID, info.ProjectID, info.VPCID, common.AVISubnetLBID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to read AVI subnet", "VPC", vpc.Id) return "", "", err @@ -436,6 +591,7 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) { path := *subnet.Path statusList, err := statusClient.List(info.OrgID, info.ProjectID, info.VPCID, common.AVISubnetLBID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to read AVI subnet status", "VPC", vpc.Id) return "", "", err @@ -446,39 +602,71 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) { return "", "", err } + if statusList.Results[0].NetworkAddress == nil { + err := fmt.Errorf("invalid status result: %+v", statusList.Results[0]) + log.Error(err, "subnet status does not have network address", "Subnet", common.AVISubnetLBID) + return "", "", err + } + cidr := *statusList.Results[0].NetworkAddress log.Info("read AVI subnet properties", "Path", path, "CIDR", cidr) return path, cidr, nil } -func (s *VPCService) CreateorUpdateVPC(obj *v1alpha1.VPC) (*model.Vpc, *common.VPCNetworkConfigInfo, error) { - // check from VPC store if vpc already exist - updateVpc := false - existingVPC := s.VpcStore.GetVPCsByNamespace(obj.Namespace) - if len(existingVPC) != 0 { // We now consider only one VPC for one namespace - updateVpc = true - log.Info("VPC already exist, updating NSX VPC object", "VPC", existingVPC[0].Id) +func (s *VPCService) GetVpcConnectivityProfile(nc *common.VPCNetworkConfigInfo, vpcConnectivityProfilePath string) (*model.VpcConnectivityProfile, error) { + parts := strings.Split(vpcConnectivityProfilePath, "/") + if len(parts) < 1 { + return nil, fmt.Errorf("failed to check VPCConnectivityProfile(%s) length", nc.VPCConnectivityProfile) } - - // read corresponding vpc network config from store - ncName, err := s.getNetworkconfigNameFromNS(obj.Namespace) + vpcConnectivityProfileName := parts[len(parts)-1] + vpcConnectivityProfile, err := s.Service.NSXClient.VPCConnectivityProfilesClient.Get(nc.Org, nc.NSXProject, vpcConnectivityProfileName) if err != nil { - log.Error(err, "failed to get network config name for VPC when creating NSX VPC", "VPC", obj.Name) - return nil, nil, err + log.Error(err, "failed to get NSX VPCConnectivityProfile object", "vpcConnectivityProfileName", vpcConnectivityProfileName) + return nil, err } - nc, _exist := s.GetVPCNetworkConfig(ncName) - if !_exist { - message := fmt.Sprintf("failed to read network config %s when creating NSX VPC", ncName) - log.Info(message) - return nil, nil, errors.New(message) + return &vpcConnectivityProfile, nil +} + +func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo, nc *common.VPCNetworkConfigInfo) (*model.Vpc, error) { + // check from VPC store if vpc already exist + ns := obj.Namespace + updateVpc := false + nsObj := &v1.Namespace{} + // get name obj + if err := s.Client.Get(ctx, types.NamespacedName{Name: obj.Namespace}, nsObj); err != nil { + log.Error(err, "unable to fetch namespace", "name", obj.Namespace) + return nil, err } - log.Info("read network config from store", "NetworkConfig", ncName) + // Return pre-created VPC resource if it is used in the VPCNetworkConfiguration + if IsPreCreatedVPC(*nc) { + preVPC, err := s.GetVPCFromNSXByPath(nc.VPCPath) + if err != nil { + log.Error(err, "Failed to get existing VPC from NSX", "vpcPath", nc.VPCPath) + return nil, err + } + return preVPC, nil + } - paths, err := s.CreatOrUpdatePrivateIPBlock(obj, nc) + // check if this namespace vpc share from others, if yes + // then check if the shared vpc created or not, if yes + // then directly return this vpc, if not, requeue + isShared, err := s.IsSharedVPCNamespaceByNS(ns) if err != nil { - log.Error(err, "failed to process private ip blocks, push event back to queue") - return nil, nil, err + return nil, err + } + + existingVPC := s.GetVPCsByNamespace(ns) + if len(existingVPC) != 0 { // We now consider only one VPC for one namespace + if isShared { + log.Info("The shared VPC already exist", "Namespace", ns) + return existingVPC[0], nil + } + updateVpc = true + log.Info("VPC already exist, updating NSX VPC object", "VPC", existingVPC[0].Id) + } else if isShared { + message := fmt.Sprintf("the shared VPC is not created yet, namespace %s", ns) + return nil, errors.New(message) } // if all private ip blocks are created, then create nsx vpc resource. @@ -491,63 +679,178 @@ func (s *VPCService) CreateorUpdateVPC(obj *v1alpha1.VPC) (*model.Vpc, *common.V nsxVPC = nil } - createdVpc, err := buildNSXVPC(obj, nc, s.NSXConfig.Cluster, paths, nsxVPC) + createdVpc, err := buildNSXVPC(obj, nsObj, *nc, s.NSXConfig.Cluster, nsxVPC, !s.NSXLBEnabled()) if err != nil { log.Error(err, "failed to build NSX VPC object") - return nil, nil, err + return nil, err } - // if there is not change in public cidr and private cidr, build partial vpc will return nil + // if there is no change in public cidr and private cidr, build partial vpc will return nil if createdVpc == nil { log.Info("no VPC changes detect, skip creating or updating process") - return existingVPC[0], &nc, nil + return existingVPC[0], nil + } + + // build NSX LBS + var createdLBS *model.LBService + if s.NSXLBEnabled() { + lbsSize := s.NSXConfig.NsxConfig.GetNSXLBSize() + vpcPath := fmt.Sprintf(VPCKey, nc.Org, nc.NSXProject, nc.Name) + var relaxScaleValidation *bool + if s.NSXConfig.NsxConfig.RelaxNSXLBScaleValication { + relaxScaleValidation = common.Bool(true) + } + createdLBS, _ = buildNSXLBS(obj, nsObj, s.NSXConfig.Cluster, lbsSize, vpcPath, relaxScaleValidation) + } + // build HAPI request + orgRoot, err := s.WrapHierarchyVPC(nc.Org, nc.NSXProject, createdVpc, createdLBS) + if err != nil { + log.Error(err, "failed to build HAPI request") + return nil, err } log.Info("creating NSX VPC", "VPC", *createdVpc.Id) - err = s.NSXClient.VPCClient.Patch(nc.Org, nc.NsxtProject, *createdVpc.Id, *createdVpc) + err = s.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) if err != nil { - log.Error(err, "failed to create VPC", "Project", nc.NsxtProject, "Namespace", obj.Namespace) + log.Error(err, "failed to create VPC", "Project", nc.NSXProject, "Namespace", obj.Namespace) // TODO: this seems to be a nsx bug, in some case, even if nsx returns failed but the object is still created. - // in this condition, we still need to read the object and update it into store, or else operator will create multiple - // vpcs for this namespace. log.Info("try to read VPC although VPC creation failed", "VPC", *createdVpc.Id) - failedVpc, rErr := s.NSXClient.VPCClient.Get(nc.Org, nc.NsxtProject, *createdVpc.Id) + failedVpc, rErr := s.NSXClient.VPCClient.Get(nc.Org, nc.NSXProject, *createdVpc.Id) + rErr = nsxutil.NSXApiError(rErr) if rErr != nil { // failed to read, but already created, we consider this scenario as success, but store may not sync with nsx log.Info("confirmed VPC is not created", "VPC", createdVpc.Id) - return nil, nil, err + return nil, err } else { - // vpc created anyway, update store, and in this scenario, we condsider creating successfully - log.Info("read VPCs from NSX after creation failed, still update VPC store", "VPC", *createdVpc.Id) - s.VpcStore.Add(&failedVpc) - return &failedVpc, &nc, nil + // vpc created anyway, in this case, we consider this vpc is created successfully and continue to realize process + log.Info("vpc created although nsx return error, continue to check realization", "VPC", *failedVpc.Id) } } // get the created vpc from nsx, it contains the path of the resources - newVpc, err := s.NSXClient.VPCClient.Get(nc.Org, nc.NsxtProject, *createdVpc.Id) + newVpc, err := s.NSXClient.VPCClient.Get(nc.Org, nc.NSXProject, *createdVpc.Id) + err = nsxutil.NSXApiError(err) if err != nil { // failed to read, but already created, we consider this scenario as success, but store may not sync with nsx log.Error(err, "failed to read VPC object after creating or updating", "VPC", createdVpc.Id) - return nil, nil, err + return nil, err } + log.V(2).Info("check VPC realization state", "VPC", *createdVpc.Id) realizeService := realizestate.InitializeRealizeState(s.Service) - if err = realizeService.CheckRealizeState(retry.DefaultRetry, *newVpc.Path, "RealizedLogicalRouter"); err != nil { + if err = realizeService.CheckRealizeState(util.NSXTDefaultRetry, *newVpc.Path, "RealizedLogicalRouter"); err != nil { log.Error(err, "failed to check VPC realization state", "VPC", *createdVpc.Id) if realizestate.IsRealizeStateError(err) { log.Error(err, "the created VPC is in error realization state, cleaning the resource", "VPC", *createdVpc.Id) - // delete the nsx vpc object and re-created in next loop + // delete the nsx vpc object and re-create it in the next loop + // TODO(gran) DeleteVPC will check VpcStore but new Vpc is not in store at this moment. Is it correct? if err := s.DeleteVPC(*newVpc.Path); err != nil { log.Error(err, "cleanup VPC failed", "VPC", *createdVpc.Id) - return nil, nil, err + return nil, err } } - return nil, nil, err + return nil, err } s.VpcStore.Add(&newVpc) - return &newVpc, &nc, nil + + // Check LBS realization + if createdLBS != nil { + newLBS, err := s.NSXClient.VPCLBSClient.Get(nc.Org, nc.NSXProject, *createdVpc.Id, *createdLBS.Id) + if err != nil { + log.Error(err, "failed to read LBS object after creating or updating", "LBS", createdLBS.Id) + return nil, err + } + s.LbsStore.Add(&newLBS) + + log.V(2).Info("check LBS realization state", "LBS", *createdLBS.Id) + realizeService := realizestate.InitializeRealizeState(s.Service) + if err = realizeService.CheckRealizeState(util.NSXTLBVSDefaultRetry, *newLBS.Path, ""); err != nil { + log.Error(err, "failed to check LBS realization state", "LBS", *createdLBS.Id) + if realizestate.IsRealizeStateError(err) { + log.Error(err, "the created LBS is in error realization state, cleaning the resource", "LBS", *createdLBS.Id) + // delete the nsx vpc object and re-create it in the next loop + if err := s.DeleteVPC(*newVpc.Path); err != nil { + log.Error(err, "cleanup VPC failed", "VPC", *createdVpc.Id) + return nil, err + } + } + return nil, err + } + } + + return &newVpc, nil +} + +func (s *VPCService) GetGatewayConnectionTypeFromConnectionPath(connectionPath string) (string, error) { + /* examples of connection_path: + /infra/distributed-gateway-connections/gateway-101 + /infra/gateway-connections/tenant-1 + */ + parts := strings.Split(connectionPath, "/") + if len(parts) != 4 || parts[1] != "infra" { + return "", fmt.Errorf("unexpected connectionPath %s", connectionPath) + } + return parts[2], nil +} + +func (s *VPCService) ValidateGatewayConnectionStatus(nc *common.VPCNetworkConfigInfo) (bool, string, error) { + // Case 1: the project has the full list of edge clusters, so if the project doesn't have edge, + // we can say that the edge is not deployed. + var projectEdges []string + project, err := s.NSXClient.ProjectClient.Get(nc.Org, nc.NSXProject, nil) + err = nsxutil.NSXApiError(err) + if err != nil { + return false, "", err + } + for _, siteInfo := range project.SiteInfos { + projectEdges = append(projectEdges, siteInfo.EdgeClusterPaths...) + } + if len(projectEdges) == 0 { + return false, common.ReasonEdgeMissingInProject, nil + } + + var connectionPaths []string // i.e. gateway connection paths + var profiles []model.VpcConnectivityProfile + var cursor *string + pageSize := int64(1000) + markedForDelete := false + res, err := s.NSXClient.VPCConnectivityProfilesClient.List(nc.Org, nc.NSXProject, cursor, &markedForDelete, nil, &pageSize, nil, nil) + err = nsxutil.NSXApiError(err) + if err != nil { + return false, "", err + } + profiles = append(profiles, res.Results...) + for _, profile := range profiles { + transitGatewayPath := *profile.TransitGatewayPath + parts := strings.Split(transitGatewayPath, "/") + transitGatewayId := parts[len(parts)-1] + res, err := s.NSXClient.TransitGatewayAttachmentClient.List(nc.Org, nc.NSXProject, transitGatewayId, nil, &markedForDelete, nil, nil, nil, nil) + err = nsxutil.NSXApiError(err) + if err != nil { + return false, "", err + } + for _, attachment := range res.Results { + connectionPaths = append(connectionPaths, *attachment.ConnectionPath) + } + } + // Case 2: there's no gateway connection paths. + if len(connectionPaths) == 0 { + return false, common.ReasonGatewayConnectionNotSet, nil + } + + // Case 3: detected distributed gateway connection which is not supported. + for _, connectionPath := range connectionPaths { + gatewayConnectionType, err := s.GetGatewayConnectionTypeFromConnectionPath(connectionPath) + if err != nil { + return false, "", err + } + if gatewayConnectionType != "gateway-connections" { + return false, common.ReasonDistributedGatewayConnectionNotSupported, nil + } + } + return true, "", nil } func (s *VPCService) Cleanup(ctx context.Context) error { @@ -558,6 +861,12 @@ func (s *VPCService) Cleanup(ctx context.Context) error { case <-ctx.Done(): return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) default: + // first clean avi subnet ports, or else vpc delete will fail + if !s.NSXLBEnabled() { + if err := CleanAviSubnetPorts(ctx, s.NSXClient.Cluster, *vpc.Path); err != nil { + return err + } + } if err := s.DeleteVPC(*vpc.Path); err != nil { return err } @@ -578,258 +887,186 @@ func (s *VPCService) Cleanup(ctx context.Context) error { } } - return nil -} - -func (service *VPCService) needUpdateRule(rule *model.Rule, externalCIDRs []string) bool { - des := rule.DestinationGroups - currentDesSet := sets.Set[string]{} - for _, group := range des { - currentDesSet.Insert(group) - } - if len(externalCIDRs) != len(currentDesSet) { - return true - } - for _, cidr := range externalCIDRs { - if !currentDesSet.Has(cidr) { - return true + // Delete NCP created resources (share/sharedResources/cert/LBAppProfile/LBPersistentProfile + sharedResources := s.ListSharedResource() + log.Info("cleaning up sharedResources", "Count", len(sharedResources)) + for _, sharedResource := range sharedResources { + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + parentPath := strings.Split(*sharedResource.ParentPath, "/") + shareId := parentPath[len(parentPath)-1] + if err := s.DeleteSharedResource(shareId, *sharedResource.Id); err != nil { + return err + } } } - return false -} - -func (service *VPCService) getIpblockCidr(blocks []string) (result []string, err error) { - for _, cidr := range blocks { - ipblock := service.PubIpblockStore.GetByKey(cidr) - if ipblock == nil { - // in case VPC using the new ipblock, search the ipblock from nsxt - // return error, and retry next time when the ipblock is synced into store - err = errors.New("ipblock not found") - log.Error(err, "failed to get public ipblock", "path", cidr) - query := fmt.Sprintf("%s:%s AND visibility:EXTERNAL", common.ResourceType, common.ResourceTypeIPBlock) - count, searcherr := service.SearchResource(common.ResourceTypeIPBlock, query, service.PubIpblockStore, nil) - if searcherr != nil { - log.Error(searcherr, "failed to query public ipblock", "query", query) - } else { - log.V(1).Info("query public ipblock", "count", count) + shares := s.ListShare() + log.Info("cleaning up shares", "Count", len(shares)) + for _, share := range shares { + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + if err := s.DeleteShare(*share.Id); err != nil { + return err } - return - } else { - result = append(result, *ipblock.Cidr) } } - return -} -func (service *VPCService) CreateOrUpdateAVIRule(vpc *model.Vpc, namespace string) error { - if !enableAviAllowRule { - return nil - } - if !nsxutil.IsLicensed(nsxutil.FeatureDFW) { - log.Info("avi rule cannot be created or updated due to no DFW license") - return nil - } - vpcInfo, err := common.ParseVPCResourcePath(*vpc.Path) - if err != nil { - log.Error(err, "failed to parse VPC Resource Path: ", *vpc.Path) - return err - } - orgId := vpcInfo.OrgID - projectId := vpcInfo.ProjectID - ruleId := AviSEIngressAllowRuleId - groupId := VPCAviSEGroupId - spId := VpcDefaultSecurityPolicyId - - if !service.checkAVISecurityPolicyExist(orgId, projectId, *vpc.Id, spId) { - return errors.New("avi security policy not found") - } - allowrule, err := service.getAVIAllowRule(orgId, projectId, *vpc.Id, spId, ruleId) - if err != nil { - log.Info("avi rule is not found, creating") - } - externalCIDRs, err := service.getIpblockCidr(vpc.ExternalIpv4Blocks) - if err != nil { - return err - } - log.Info("avi rule get external cidr", "cidr", externalCIDRs) - if allowrule != nil { - if !service.needUpdateRule(allowrule, externalCIDRs) { - log.Info("avi rule is not changed, skip updating avi rule") - return nil - } else { - log.Info("avi rule changed", "previous", allowrule.DestinationGroups, "current", externalCIDRs) + certs := s.ListCert() + log.Info("cleaning up certificates", "Count", len(certs)) + for _, cert := range certs { + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + if err := s.DeleteCert(*cert.Id); err != nil { + return err + } } } - group, err := service.getorCreateAVIGroup(orgId, projectId, *vpc.Id, groupId) - if err != nil { - log.Error(err, "failed to get avi group", "group", groupId) - return err + lbAppProfiles := s.ListLBAppProfile() + log.Info("cleaning up lbAppProfiles", "Count", len(lbAppProfiles)) + for _, lbAppProfile := range lbAppProfiles { + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + if err := s.DeleteLBAppProfile(*lbAppProfile.Id); err != nil { + return err + } + } } - newrule, err := service.buildAVIAllowRule(vpc, externalCIDRs, *group.Path, ruleId, projectId) - log.Info("creating avi rule", "rule", newrule) - if err != nil { - log.Error(err, "failed to build avi rule", "rule", newrule) - return err + lbPersistenceProfiles := s.ListLBPersistenceProfile() + log.Info("cleaning up lbPersistenceProfiles", "Count", len(lbPersistenceProfiles)) + for _, lbPersistenceProfile := range lbPersistenceProfiles { + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + if err := s.DeleteLBPersistenceProfile(*lbPersistenceProfile.Id); err != nil { + return err + } + } } - err = service.NSXClient.VPCRuleClient.Patch(orgId, projectId, *vpc.Id, spId, *newrule.Id, *newrule) - if err != nil { - log.Error(err, "failed to create avi rule", "rule", newrule) - return err - } - nsxrule, err := service.NSXClient.VPCRuleClient.Get(orgId, projectId, *vpc.Id, spId, *newrule.Id) - if err != nil { - log.Error(err, "failed to get avi rule", "rule", nsxrule) - return err + lbMonitorProfiles := s.ListLBMonitorProfile() + log.Info("cleaning up lbMonitorProfiles", "Count", len(lbMonitorProfiles)) + for _, lbMonitorProfile := range lbMonitorProfiles { + select { + case <-ctx.Done(): + return errors.Join(nsxutil.TimeoutFailed, ctx.Err()) + default: + if err := s.DeleteLBMonitorProfile(*lbMonitorProfile.Id); err != nil { + return err + } + } } - service.RuleStore.Add(&nsxrule) - log.Info("created avi rule successfully") + // We don't clean client_ssl_profile as client_ssl_profile is not created by ncp or nsx-operator return nil } -func (service *VPCService) getorCreateAVIGroup(orgId string, projectId string, vpcId string, groupId string) (*model.Group, error) { - groupPtr, err := service.getAVIGroup(orgId, projectId, vpcId, groupId) - if err != nil { - log.Info("create avi group", "group", groupId) - groupPtr, err = service.createAVIGroup(orgId, projectId, vpcId, groupId) +func (service *VPCService) ListVPCInfo(ns string) []common.VPCResourceInfo { + var VPCInfoList []common.VPCResourceInfo + nc := service.GetVPCNetworkConfigByNamespace(ns) + // Return the pre-created VPC resource info if it is set in VPCNetworkConfiguration. + if nc != nil && IsPreCreatedVPC(*nc) { + vpcResourceInfo, err := common.ParseVPCResourcePath(nc.VPCPath) if err != nil { - log.Error(err, "failed to create avi group", "group", groupId) - return groupPtr, err + log.Error(err, "Failed to get vpc info from vpc path", "vpc path", nc.VPCPath) + } else { + VPCInfoList = append(VPCInfoList, vpcResourceInfo) } - service.GroupStore.Add(groupPtr) - } - return groupPtr, err -} - -func (service *VPCService) buildAVIGroupTag(vpcId string) []model.Tag { - return []model.Tag{ - { - Scope: common.String(common.TagScopeCluster), - Tag: common.String(service.NSXConfig.Cluster), - }, - { - Scope: common.String(common.TagScopeVersion), - Tag: common.String(strings.Join(common.TagValueVersion, ".")), - }, - { - Scope: common.String(common.TagScopeVPCCRUID), - Tag: common.String(vpcId), - }, - { - Scope: common.String(common.TagScopeGroupType), - Tag: common.String(common.TagValueGroupAvi), - }, - } -} - -func (service *VPCService) createAVIGroup(orgId string, projectId string, vpcId string, groupId string) (*model.Group, error) { - group := model.Group{} - group.Tags = service.buildAVIGroupTag(vpcId) - expression := service.buildExpression("Condition", "VpcSubnet", "AVI_SUBNET_LB|", "Tag", "EQUALS", "EQUALS") - group.Expression = []*data.StructValue{expression} - group.DisplayName = common.String(groupId) - - err := service.NSXClient.VpcGroupClient.Patch(orgId, projectId, vpcId, groupId, group) - if err != nil { - return &group, err - } - nsxgroup, err := service.NSXClient.VpcGroupClient.Get(orgId, projectId, vpcId, groupId) - return &nsxgroup, err -} - -func (service *VPCService) buildExpression(resource_type, member_type, value, key, operator, scope_op string) *data.StructValue { - return data.NewStructValue( - "", - map[string]data.DataValue{ - "resource_type": data.NewStringValue(resource_type), - "member_type": data.NewStringValue(member_type), - "value": data.NewStringValue(value), - "key": data.NewStringValue(key), - "operator": data.NewStringValue(operator), - "scope_operator": data.NewStringValue(scope_op), - }, - ) -} - -func (service *VPCService) buildAVIAllowRule(obj *model.Vpc, externalCIDRs []string, groupId, ruleId, projectId string) (*model.Rule, error) { - rule := &model.Rule{} - rule.Action = common.String(model.Rule_ACTION_ALLOW) - rule.Direction = common.String(model.Rule_DIRECTION_IN_OUT) - rule.Scope = append(rule.Scope, groupId) - rule.SequenceNumber = common.Int64(math.MaxInt32 - 1) - rule.DestinationGroups = externalCIDRs - rule.SourceGroups = append(rule.SourceGroups, "Any") - name := fmt.Sprintf("PROJECT-%s-VPC-%s-%s", projectId, *obj.Id, ruleId) - rule.DisplayName = common.String(name) - rule.Id = common.String(ruleId) - rule.Services = []string{"ANY"} - rule.IsDefault = common.Bool(true) - tags := []model.Tag{ - { - Scope: common.String(common.TagScopeCluster), - Tag: common.String(service.NSXConfig.Cluster), - }, - { - Scope: common.String(common.TagScopeVersion), - Tag: common.String(strings.Join(common.TagValueVersion, ".")), - }, - } - rule.Tags = tags - return rule, nil -} - -func (service *VPCService) getAVIAllowRule(orgId string, projectId string, vpcId string, spId string, ruleId string) (*model.Rule, error) { - key := fmt.Sprintf(RuleKey, orgId, projectId, vpcId, spId, ruleId) - rule := service.RuleStore.GetByKey(key) - if rule == nil { - log.Info("avi rule not found", "key", key) - return nil, errors.New("avi rule not found") - } - return rule, nil -} - -func (service *VPCService) getAVIGroup(orgId string, projectId string, vpcId string, groupId string) (*model.Group, error) { - key := fmt.Sprintf(GroupKey, orgId, projectId, vpcId, groupId) - group := service.GroupStore.GetByKey(key) - var err error - if group == nil { - log.Info("avi se group not found", "key", key) - err = errors.New("avi se group not found") - } - return group, err -} - -// checkAVISecurityPolicyExist returns true if security policy for that VPC already exists -// this security policy created by NSXT once VPC created -// if not found, wait until it created -func (service *VPCService) checkAVISecurityPolicyExist(orgId string, projectId string, vpcId string, spId string) bool { - key := fmt.Sprintf(SecurityPolicyKey, orgId, projectId, vpcId, spId) - sp := service.SecurityPolicyStore.GetByKey(key) - if sp != nil { - return true - } - nsxtsp, err := service.NSXClient.VPCSecurityClient.Get(orgId, projectId, vpcId, spId) - if err != nil { - log.Error(err, "failed to get avi security policy", "key", key) - return false + return VPCInfoList } - service.SecurityPolicyStore.Add(&nsxtsp) - return true -} -func (service *VPCService) ListVPCInfo(ns string) []common.VPCResourceInfo { - var VPCInfoList []common.VPCResourceInfo + // List VPCs from local store. vpcs := service.GetVPCsByNamespace(ns) // Transparently call the VPCService.GetVPCsByNamespace method for _, v := range vpcs { vpcResourceInfo, err := common.ParseVPCResourcePath(*v.Path) if err != nil { log.Error(err, "Failed to get vpc info from vpc path", "vpc path", *v.Path) } - vpcResourceInfo.ExternalIPv4Blocks = v.ExternalIpv4Blocks vpcResourceInfo.PrivateIpv4Blocks = v.PrivateIpv4Blocks VPCInfoList = append(VPCInfoList, vpcResourceInfo) } return VPCInfoList } + +func (s *VPCService) GetNSXLBSPath(lbsId string) string { + vpcLBS := s.LbsStore.GetByKey(lbsId) + if vpcLBS == nil { + return "" + } + return *vpcLBS.Path +} + +func GetAlbEndpoint(cluster *nsx.Cluster) error { + _, err := cluster.HttpGet(albEndpointPath) + return err +} + +func (vpcService *VPCService) NSXLBEnabled() bool { + lbProviderMutex.Lock() + defer lbProviderMutex.Unlock() + + if lbProvider == "" { + lbProvider = vpcService.getLBProvider() + } + return lbProvider == LBProviderNSX +} + +func (vpcService *VPCService) getLBProvider() string { + // if no Alb endpoint found, return nsx-lb + // if found, and nsx lbs found, return nsx-lb + // else return avi + if !vpcService.Service.NSXConfig.UseAVILoadBalancer { + return LBProviderNSX + } + albEndpointFound := false + if err := retry.OnError(retry.DefaultBackoff, func(err error) bool { + if err == nil { + return false + } + if errors.Is(err, nsxutil.HttpCommonError) { + return true + } else { + return false + } + }, func() error { + return GetAlbEndpoint(vpcService.Service.NSXClient.Cluster) + }); err == nil { + albEndpointFound = true + } + if !albEndpointFound { + return LBProviderNSX + } + if len(vpcService.LbsStore.List()) > 0 { + return LBProviderNSX + } + return LBProviderAVI +} + +func (service *VPCService) GetVPCFromNSXByPath(vpcPath string) (*model.Vpc, error) { + vpcResInfo, err := common.ParseVPCResourcePath(vpcPath) + if err != nil { + log.Error(err, "failed to parse VPCResourceInfo from the given VPC path", "VPC", vpcPath) + return nil, err + } + vpc, err := service.NSXClient.VPCClient.Get(vpcResInfo.OrgID, vpcResInfo.ProjectID, vpcResInfo.VPCID) + err = nsxutil.NSXApiError(err) + if err != nil { + log.Error(err, "failed to read VPC object from NSX", "VPC", vpcPath) + return nil, err + } + + return &vpc, nil +} + +func IsPreCreatedVPC(nc common.VPCNetworkConfigInfo) bool { + return nc.VPCPath != "" +} diff --git a/pkg/nsx/services/vpc/vpc_test.go b/pkg/nsx/services/vpc/vpc_test.go index 0d77d82f1..23a9e8564 100644 --- a/pkg/nsx/services/vpc/vpc_test.go +++ b/pkg/nsx/services/vpc/vpc_test.go @@ -33,10 +33,6 @@ var ( vpcID3 = "ns-vpc-uid-3" IPv4Type = "IPv4" cluster = "k8scl-one" - tagScopeVPCCRName = common.TagScopeVPCCRName - tagScopeVPCCRUID = common.TagScopeVPCCRUID - tagValueVPCCRName = "vpcA" - tagValueVPCCRUID = "uidA" tagScopeCluster = common.TagScopeCluster tagScopeNamespace = common.TagScopeNamespace ) @@ -75,13 +71,83 @@ func createService(t *testing.T) (*VPCService, *gomock.Controller, *mocks.MockVp }, }, }, - VpcStore: vpcStore, - VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, - VPCNSNetworkConfigMap: map[string]string{}, + VpcStore: vpcStore, + VPCNetworkConfigStore: VPCNetworkInfoStore{ + VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, + }, + VPCNSNetworkConfigStore: VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: map[string]string{}, + }, } return service, mockCtrl, mockVpcclient } +type fakeProjectClient struct{} + +func (c fakeProjectClient) Get(orgIdParam string, projectIdParam string, shortFormatParam *bool) (model.Project, error) { + return model.Project{}, nil +} + +func (c fakeProjectClient) Delete(orgIdParam string, projectIdParam string, isRecursiveParam *bool) error { + return nil +} + +func (c fakeProjectClient) List(orgIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, instanceIdParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.ProjectListResult, error) { + return model.ProjectListResult{}, nil +} + +func (c fakeProjectClient) Patch(orgIdParam string, projectIdParam string, projectParam model.Project) error { + return nil +} + +func (c fakeProjectClient) Update(orgIdParam string, projectIdParam string, projectParam model.Project) (model.Project, error) { + return model.Project{}, nil +} + +type fakeVPCConnectivityProfilesClient struct{} + +func (c fakeVPCConnectivityProfilesClient) Delete(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string) error { + return nil +} + +func (c fakeVPCConnectivityProfilesClient) Get(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string) (model.VpcConnectivityProfile, error) { + return model.VpcConnectivityProfile{}, nil +} + +func (c fakeVPCConnectivityProfilesClient) List(orgIdParam string, projectIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.VpcConnectivityProfileListResult, error) { + return model.VpcConnectivityProfileListResult{}, nil +} + +func (c fakeVPCConnectivityProfilesClient) Patch(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string, vpcConnectivityProfileParam model.VpcConnectivityProfile) error { + return nil +} + +func (c fakeVPCConnectivityProfilesClient) Update(orgIdParam string, projectIdParam string, vpcConnectivityProfileIdParam string, vpcConnectivityProfileParam model.VpcConnectivityProfile) (model.VpcConnectivityProfile, error) { + return model.VpcConnectivityProfile{}, nil +} + +type fakeTransitGatewayAttachmentClient struct{} + +func (c fakeTransitGatewayAttachmentClient) Delete(orgIdParam string, projectIdParam string, transitGatewayIdParam string, attachmentIdParam string) error { + return nil +} + +func (c fakeTransitGatewayAttachmentClient) Get(orgIdParam string, projectIdParam string, transitGatewayIdParam string, attachmentIdParam string) (model.TransitGatewayAttachment, error) { + return model.TransitGatewayAttachment{}, nil +} + +func (c fakeTransitGatewayAttachmentClient) List(orgIdParam string, projectIdParam string, transitGatewayIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.TransitGatewayAttachmentListResult, error) { + return model.TransitGatewayAttachmentListResult{}, nil +} + +func (c fakeTransitGatewayAttachmentClient) Patch(orgIdParam string, projectIdParam string, transitGatewayIdParam string, attachmentIdParam string, transitGatewayAttachmentParam model.TransitGatewayAttachment) error { + return nil +} + +func (c fakeTransitGatewayAttachmentClient) Update(orgIdParam string, projectIdParam string, transitGatewayIdParam string, attachmentIdParam string, transitGatewayAttachmentParam model.TransitGatewayAttachment) (model.TransitGatewayAttachment, error) { + return model.TransitGatewayAttachment{}, nil +} + func TestGetNetworkConfigFromNS(t *testing.T) { service, _, _ := createService(t) k8sClient := service.Client.(*mock_client.MockClient) @@ -90,14 +156,14 @@ func TestGetNetworkConfigFromNS(t *testing.T) { k8sClient.EXPECT().Get(ctx, gomock.Any(), mockNs).Return(fakeErr).Do(func(_ context.Context, k client.ObjectKey, obj client.Object, option ...client.GetOption) error { return nil }) - ns, err := service.getNetworkconfigNameFromNS("test") + ns, err := service.GetNetworkconfigNameFromNS("test") assert.Equal(t, fakeErr, err) assert.Equal(t, "", ns) k8sClient.EXPECT().Get(ctx, gomock.Any(), mockNs).Return(nil).Do(func(_ context.Context, k client.ObjectKey, obj client.Object, option ...client.GetOption) error { return nil }) - ns, err = service.getNetworkconfigNameFromNS("test") + ns, err = service.GetNetworkconfigNameFromNS("test") assert.NotNil(t, err) assert.Equal(t, "", ns) @@ -109,7 +175,7 @@ func TestGetNetworkConfigFromNS(t *testing.T) { k8sClient.EXPECT().Get(ctx, gomock.Any(), mockNs).Return(nil).Do(func(_ context.Context, k client.ObjectKey, obj client.Object, option ...client.GetOption) error { return nil }) - ns, err = service.getNetworkconfigNameFromNS("test") + ns, err = service.GetNetworkconfigNameFromNS("test") assert.Nil(t, err) assert.Equal(t, "test-name", ns) @@ -117,7 +183,7 @@ func TestGetNetworkConfigFromNS(t *testing.T) { obj.SetAnnotations(map[string]string{"nsx.vmware.com/vpc_network_config": "test-nc"}) return nil }) - ns, err = service.getNetworkconfigNameFromNS("test") + ns, err = service.GetNetworkconfigNameFromNS("test") assert.Nil(t, err) assert.Equal(t, "test-nc", ns) } @@ -135,7 +201,7 @@ func TestGetSharedVPCNamespaceFromNS(t *testing.T) { expected string }{ {"1", "test-ns-1", map[string]string{"nsx.vmware.com/vpc_network_config": "default"}, ""}, - {"2", "test-ns-2", map[string]string{"nsx.vmware.com/vpc_network_config": "infra", "nsx.vmware.com/vpc_name": "kube-system/fake_vpc"}, "kube-system"}, + {"2", "test-ns-2", map[string]string{"nsx.vmware.com/vpc_network_config": "infra", "nsx.vmware.com/shared_vpc_namespace": "kube-system"}, "kube-system"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -174,16 +240,20 @@ func TestGetDefaultNetworkConfig(t *testing.T) { } func TestGetVPCsByNamespace(t *testing.T) { - vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeVPCCRUID: indexFunc}) + vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{}) resourceStore := common.ResourceStore{ Indexer: vpcCacheIndexer, BindingType: model.VpcBindingType(), } vpcStore := &VPCStore{ResourceStore: resourceStore} service := &VPCService{ - Service: common.Service{NSXClient: nil}, - VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, - VPCNSNetworkConfigMap: map[string]string{}, + Service: common.Service{NSXClient: nil}, + VPCNetworkConfigStore: VPCNetworkInfoStore{ + VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, + }, + VPCNSNetworkConfigStore: VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: map[string]string{}, + }, } service.VpcStore = vpcStore type args struct { @@ -202,14 +272,6 @@ func TestGetVPCsByNamespace(t *testing.T) { Scope: &tagScopeNamespace, Tag: &ns1, }, - { - Scope: &tagScopeVPCCRName, - Tag: &tagValueVPCCRName, - }, - { - Scope: &tagScopeVPCCRUID, - Tag: &tagValueVPCCRUID, - }, } ns2 := "test-ns-2" tag2 := []model.Tag{ @@ -221,14 +283,6 @@ func TestGetVPCsByNamespace(t *testing.T) { Scope: &tagScopeNamespace, Tag: &ns2, }, - { - Scope: &tagScopeVPCCRName, - Tag: &tagValueVPCCRName, - }, - { - Scope: &tagScopeVPCCRUID, - Tag: &tagValueVPCCRUID, - }, } infraNs := "kube-system" tag3 := []model.Tag{ @@ -240,14 +294,6 @@ func TestGetVPCsByNamespace(t *testing.T) { Scope: &tagScopeNamespace, Tag: &infraNs, }, - { - Scope: &tagScopeVPCCRName, - Tag: &tagValueVPCCRName, - }, - { - Scope: &tagScopeVPCCRUID, - Tag: &tagValueVPCCRUID, - }, } vpc1 := model.Vpc{ @@ -317,227 +363,300 @@ func TestListVPCInfo(t *testing.T) { } -type MockSecurityPoliciesClient struct { - SP model.SecurityPolicy - Err error -} - -func (spClient *MockSecurityPoliciesClient) Delete(orgIdParam string, projectIdParam string, vpcIdParam string, groupIdParam string) error { - return spClient.Err -} - -func (spClient *MockSecurityPoliciesClient) Get(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string) (model.SecurityPolicy, error) { - return spClient.SP, spClient.Err -} - -func (spClient *MockSecurityPoliciesClient) List(orgIdParam string, projectIdParam string, vpcIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includeRuleCountParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.SecurityPolicyListResult, error) { - return model.SecurityPolicyListResult{}, spClient.Err -} - -func (spClient *MockSecurityPoliciesClient) Patch(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy) error { - return spClient.Err -} -func (spClient *MockSecurityPoliciesClient) Update(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy) (model.SecurityPolicy, error) { - return spClient.SP, spClient.Err -} -func (spClient *MockSecurityPoliciesClient) Revise(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, securityPolicyParam model.SecurityPolicy, anchorPathParam *string, operationParam *string) (model.SecurityPolicy, error) { - return model.SecurityPolicy{}, spClient.Err -} - -type MockGroupClient struct { - Group model.Group - Err error -} - -func (groupClient *MockGroupClient) Delete(orgIdParam string, projectIdParam string, vpcIdParam string, groupIdParam string) error { - return groupClient.Err -} - -func (groupClient *MockGroupClient) Get(orgIdParam string, projectIdParam string, vpcIdParam string, groupIdParam string) (model.Group, error) { - return groupClient.Group, groupClient.Err -} - -func (groupClient *MockGroupClient) List(orgIdParam string, projectIdParam string, vpcIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, memberTypesParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.GroupListResult, error) { - return model.GroupListResult{}, groupClient.Err -} - -func (groupClient *MockGroupClient) Patch(orgIdParam string, projectIdParam string, vpcIdParam string, groupIdParam string, groupParam model.Group) error { - return groupClient.Err -} -func (groupClient *MockGroupClient) Update(orgIdParam string, projectIdParam string, vpcIdParam string, groupIdParam string, groupParam model.Group) (model.Group, error) { - return groupClient.Group, groupClient.Err -} +func TestNSXLBEnabled(t *testing.T) { + vpcService := &VPCService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + UseAVILoadBalancer: false, + }, + }, + NSXClient: &nsx.Client{ + Cluster: &nsx.Cluster{}, + }, + }, + LbsStore: &LBSStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBServiceBindingType(), + }}, + } -type MockRuleClient struct { - Rule model.Rule - Err error + // Test when UseAVILoadBalancer is false + vpcService.Service.NSXConfig.UseAVILoadBalancer = false + assert.True(t, vpcService.NSXLBEnabled()) } -func (ruleClient *MockRuleClient) Delete(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, ruleIdParam string) error { - return ruleClient.Err -} +func TestGetLbProvider(t *testing.T) { + vpcService := &VPCService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + UseAVILoadBalancer: false, + }, + }, + NSXClient: &nsx.Client{ + Cluster: &nsx.Cluster{}, + }, + }, + LbsStore: &LBSStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBServiceBindingType(), + }}, + } + // Test when UseAVILoadBalancer is false + lbProvider := vpcService.getLBProvider() + assert.Equal(t, LBProviderNSX, lbProvider) + + vpcService.Service.NSXConfig.NsxConfig.UseAVILoadBalancer = true + // Test when UseAVILoadBalancer is true and Alb endpoint found, but no nsx lbs found + patch := gomonkey.ApplyPrivateMethod(reflect.TypeOf(vpcService.Service.NSXClient.Cluster), "HttpGet", func(_ *nsx.Cluster, path string) (map[string]interface{}, error) { + return nil, nil + }) + lbProvider = vpcService.getLBProvider() + assert.Equal(t, LBProviderAVI, lbProvider) + patch.Reset() -func (ruleClient *MockRuleClient) Get(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, ruleIdParam string) (model.Rule, error) { - return ruleClient.Rule, ruleClient.Err -} -func (ruleClient *MockRuleClient) List(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.RuleListResult, error) { - return model.RuleListResult{}, ruleClient.Err -} + // Test when UseAVILoadBalancer is true, get alb endpoint common error + retry := 0 + patch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(vpcService.Service.NSXClient.Cluster), "HttpGet", func(_ *nsx.Cluster, path string) (map[string]interface{}, error) { + retry++ + return nil, util.HttpCommonError + }) + lbProvider = vpcService.getLBProvider() + assert.Equal(t, LBProviderNSX, lbProvider) + assert.Equal(t, 4, retry) + patch.Reset() -func (ruleClient *MockRuleClient) Patch(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, ruleIdParam string, ruleParam model.Rule) error { - return ruleClient.Err -} + // Test when UseAVILoadBalancer is true, get alb endpoint not found error + retry = 0 + patch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(vpcService.Service.NSXClient.Cluster), "HttpGet", func(_ *nsx.Cluster, path string) (map[string]interface{}, error) { + retry++ + return nil, util.HttpNotFoundError + }) + lbProvider = vpcService.getLBProvider() + assert.Equal(t, LBProviderNSX, lbProvider) + assert.Equal(t, 1, retry) + patch.Reset() -func (ruleClient *MockRuleClient) Update(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, ruleIdParam string, ruleParam model.Rule) (model.Rule, error) { - return ruleClient.Rule, ruleClient.Err -} + // Test when UseAVILoadBalancer is true, Alb endpoint found, and NSX lbs found + patch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(vpcService.Service.NSXClient.Cluster), "HttpGet", func(_ *nsx.Cluster, path string) (map[string]interface{}, error) { + return nil, nil + }) + vpcService.LbsStore.Add(&model.LBService{Id: common.String("12345")}) + lbProvider = vpcService.getLBProvider() + assert.Equal(t, LBProviderNSX, lbProvider) + patch.Reset() -func (ruleClient *MockRuleClient) Revise(orgIdParam string, projectIdParam string, vpcIdParam string, securityPolicyIdParam string, ruleIdParam string, ruleParam model.Rule, anchorPathParam *string, operationParam *string) (model.Rule, error) { - return model.Rule{}, ruleClient.Err + // Test when UseAVILoadBalancer is true, Alb endpoint found, and no NSX lbs found + patch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(vpcService.Service.NSXClient.Cluster), "HttpGet", func(_ *nsx.Cluster, path string) (map[string]interface{}, error) { + return nil, nil + }) + lbs := vpcService.LbsStore.GetByKey("12345") + err := vpcService.LbsStore.Delete(lbs) + assert.Equal(t, err, nil) + lbProvider = vpcService.getLBProvider() + assert.Equal(t, LBProviderAVI, lbProvider) + patch.Reset() } -func TestCreateOrUpdateAVIRule(t *testing.T) { - aviRuleCacheIndexer := cache.NewIndexer(keyFuncAVI, nil) - resourceStore := common.ResourceStore{ - Indexer: aviRuleCacheIndexer, - BindingType: model.VpcBindingType(), - } - ruleStore := &AviRuleStore{ResourceStore: resourceStore} - resourceStore1 := common.ResourceStore{ - Indexer: aviRuleCacheIndexer, - BindingType: model.GroupBindingType(), - } - groupStore := &AviGroupStore{ResourceStore: resourceStore1} - resourceStore2 := common.ResourceStore{ - Indexer: aviRuleCacheIndexer, - BindingType: model.SecurityPolicyBindingType(), +func TestGetGatewayConnectionTypeFromConnectionPath(t *testing.T) { + tests := []struct { + name string + path string + expectedType string + expectedError error + }{ + { + name: "ValidPath", + path: "/infra/distributed-gateway-connections/gateway-101", + expectedType: "distributed-gateway-connections", + expectedError: nil, + }, + { + name: "InvalidPath", + path: "invalidPath", + expectedType: "", + expectedError: fmt.Errorf("unexpected connectionPath invalidPath"), + }, } - spStore := &AviSecurityPolicyStore{ResourceStore: resourceStore2} - - service := &VPCService{ - Service: common.Service{NSXClient: nil}, - VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, - VPCNSNetworkConfigMap: map[string]string{}, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + service, _, _ := createService(t) + observedType, observedError := service.GetGatewayConnectionTypeFromConnectionPath(tt.path) + assert.Equal(t, tt.expectedType, observedType) + assert.Equal(t, tt.expectedError, observedError) + }) } +} - service.RuleStore = ruleStore - service.GroupStore = groupStore - service.SecurityPolicyStore = spStore - - ns1 := "test-ns-1" - tag1 := []model.Tag{ - { - Scope: &tagScopeCluster, - Tag: &cluster, - }, +func TestValidateGatewayConnectionStatus(t *testing.T) { + tests := []struct { + name string + prepareFunc func(*testing.T, *VPCService) *gomonkey.Patches + vpcNetworkConfigInfo common.VPCNetworkConfigInfo + expectedReady bool + expectedReason string + expectedError error + }{ { - Scope: &tagScopeNamespace, - Tag: &ns1, + name: "EdgeMissingInProject", + prepareFunc: func(_ *testing.T, service *VPCService) (patches *gomonkey.Patches) { + patches = gomonkey.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.ProjectClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.Project{}, + nil, + }, + Times: 1, + }}) + return patches + }, + vpcNetworkConfigInfo: common.VPCNetworkConfigInfo{ + Org: "default", + NSXProject: "project-quality", + }, + expectedReady: false, + expectedReason: "EdgeMissingInProject", + expectedError: nil, }, { - Scope: &tagScopeVPCCRName, - Tag: &tagValueVPCCRName, + name: "GatewayConnectionNotSet", + prepareFunc: func(_ *testing.T, service *VPCService) (patches *gomonkey.Patches) { + patches = gomonkey.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.ProjectClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.Project{ + SiteInfos: []model.SiteInfo{ + {EdgeClusterPaths: []string{"edge"}}, + }, + }, + nil, + }, + Times: 1, + }}) + patches.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCConnectivityProfilesClient), "List", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.VpcConnectivityProfileListResult{ + Results: []model.VpcConnectivityProfile{ + { + TransitGatewayPath: common.String("a/b"), + }, + }, + }, + nil, + }, + Times: 1, + }}) + patches.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCConnectivityProfilesClient), "List", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.VpcConnectivityProfileListResult{ + Results: []model.VpcConnectivityProfile{ + { + TransitGatewayPath: common.String("a/b"), + }, + }, + }, + nil, + }, + Times: 1, + }}) + patches.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.TransitGatewayAttachmentClient), "List", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.TransitGatewayAttachmentListResult{ + Results: []model.TransitGatewayAttachment{}, + }, + nil, + }, + Times: 1, + }}) + return patches + }, + vpcNetworkConfigInfo: common.VPCNetworkConfigInfo{ + Org: "default", + NSXProject: "project-quality", + }, + expectedReady: false, + expectedReason: "GatewayConnectionNotSet", + expectedError: nil, }, { - Scope: &tagScopeVPCCRUID, - Tag: &tagValueVPCCRUID, + name: "DistributedGatewayConnectionNotSupported", + prepareFunc: func(_ *testing.T, service *VPCService) (patches *gomonkey.Patches) { + patches = gomonkey.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.ProjectClient), "Get", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.Project{ + SiteInfos: []model.SiteInfo{ + {EdgeClusterPaths: []string{"edge"}}, + }, + }, + nil, + }, + Times: 1, + }}) + patches.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCConnectivityProfilesClient), "List", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.VpcConnectivityProfileListResult{ + Results: []model.VpcConnectivityProfile{ + { + TransitGatewayPath: common.String("a/b"), + }, + }, + }, + nil, + }, + Times: 1, + }}) + patches.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCConnectivityProfilesClient), "List", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.VpcConnectivityProfileListResult{ + Results: []model.VpcConnectivityProfile{ + { + TransitGatewayPath: common.String("a/b"), + }, + }, + }, + nil, + }, + Times: 1, + }}) + patches.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.TransitGatewayAttachmentClient), "List", []gomonkey.OutputCell{{ + Values: gomonkey.Params{ + model.TransitGatewayAttachmentListResult{ + Results: []model.TransitGatewayAttachment{ + { + ConnectionPath: common.String("/infra/distributed-gateway-connections/gateway-101"), + }, + }, + }, + nil, + }, + Times: 1, + }}) + return patches + }, + vpcNetworkConfigInfo: common.VPCNetworkConfigInfo{ + Org: "default", + NSXProject: "project-quality", + }, + expectedReady: false, + expectedReason: "DistributedGatewayConnectionNotSupported", + expectedError: nil, }, } - path1 := "/orgs/default/projects/project_1/vpcs/vpc1" - vpc1 := model.Vpc{ - Path: &path1, - DisplayName: &vpcName1, - Id: &vpcID1, - Tags: tag1, - IpAddressType: &IPv4Type, - PrivateIpv4Blocks: []string{"1.1.1.0/24"}, - ExternalIpv4Blocks: []string{"2.2.2.0/24"}, - } - - // feature not supported - enableAviAllowRule = false - err := service.CreateOrUpdateAVIRule(&vpc1, ns1) - assert.Equal(t, err, nil) - - // enable feature - enableAviAllowRule = true - spClient := MockSecurityPoliciesClient{} - - service.NSXClient = &nsx.Client{} - service.NSXClient.VPCSecurityClient = &spClient - service.NSXConfig = &config.NSXOperatorConfig{} - service.NSXConfig.CoeConfig = &config.CoeConfig{} - service.NSXConfig.Cluster = "k8scl_one" - sppath1 := "/orgs/default/projects/project_1/vpcs/vpc1/security-policies/sp1" - sp := model.SecurityPolicy{ - Path: &sppath1, - } - util.UpdateLicense(util.FeatureDFW, true) - - // security policy not found - spClient.SP = sp - notFound := errors.New("avi security policy not found") - spClient.Err = notFound - err = service.CreateOrUpdateAVIRule(&vpc1, ns1) - assert.Equal(t, err, notFound) - - // security policy found, get rule, failed to get external CIDR - rulepath1 := fmt.Sprintf("/orgs/default/projects/project_1/vpcs/ns-vpc-uid-1/security-policies/default-layer3-section/rules/%s", AviSEIngressAllowRuleId) - rule := model.Rule{ - Path: &rulepath1, - DestinationGroups: []string{"2.2.2.0/24"}, - } - ruleStore.Add(&rule) - spClient.Err = nil - resulterr := errors.New("get external ipblock failed") - patch := gomonkey.ApplyPrivateMethod(reflect.TypeOf(service), "getIpblockCidr", func(_ *VPCService, cidr []string) ([]string, error) { - return []string{}, resulterr - }) - err = service.CreateOrUpdateAVIRule(&vpc1, ns1) - patch.Reset() - assert.Equal(t, err, resulterr) - // security policy found, get rule, get external CIDR which matched - spClient.Err = nil - resulterr = errors.New("get external ipblock failed") - patch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(service), "getIpblockCidr", func(_ *VPCService, cidr []string) ([]string, error) { - return []string{"2.2.2.0/24"}, nil - }) - err = service.CreateOrUpdateAVIRule(&vpc1, ns1) - patch.Reset() - assert.Equal(t, err, nil) - - // security policy found, get external CIDR, create group failed - patch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(service), "getIpblockCidr", func(_ *VPCService, cidr []string) ([]string, error) { - return []string{"192.168.0.0/16"}, nil - }) - defer patch.Reset() - groupClient := MockGroupClient{Err: nil} - service.NSXClient.VpcGroupClient = &groupClient - grouppath1 := "/orgs/default/projects/project_1/vpcs/vpc1/groups/group1" - group := model.Group{ - Path: &grouppath1, + service, _, _ := createService(t) + service.NSXClient.ProjectClient = fakeProjectClient{} + service.NSXClient.VPCConnectivityProfilesClient = fakeVPCConnectivityProfilesClient{} + service.NSXClient.TransitGatewayAttachmentClient = fakeTransitGatewayAttachmentClient{} + for _, tt := range tests { + t.Run(tt.name, func(*testing.T) { + if tt.prepareFunc != nil { + patches := tt.prepareFunc(t, service) + defer patches.Reset() + } + ready, reason, err := service.ValidateGatewayConnectionStatus(&tt.vpcNetworkConfigInfo) + assert.Equal(t, tt.expectedReady, ready) + assert.Equal(t, tt.expectedReason, reason) + assert.Equal(t, tt.expectedError, err) + return + }) } - groupClient.Group = group - groupClient.Err = errors.New("create avi group error") - service.NSXConfig = &config.NSXOperatorConfig{} - service.NSXConfig.CoeConfig = &config.CoeConfig{} - service.NSXConfig.Cluster = "k8scl-one" - err = service.CreateOrUpdateAVIRule(&vpc1, ns1) - assert.Equal(t, err, groupClient.Err) - - // security policy found, get external CIDR, create group, create rule failed - groupClient.Err = nil - ruleClient := MockRuleClient{} - service.NSXClient.VPCRuleClient = &ruleClient - - ruleClient.Rule = rule - ruleClient.Err = errors.New("create avi rule error") - err = service.CreateOrUpdateAVIRule(&vpc1, ns1) - assert.Equal(t, err, ruleClient.Err) - - // security policy found, get external CIDR, create group, create rule - ruleClient.Err = nil - err = service.CreateOrUpdateAVIRule(&vpc1, ns1) - assert.Equal(t, err, nil) } diff --git a/pkg/nsx/services/vpc/wrap.go b/pkg/nsx/services/vpc/wrap.go new file mode 100644 index 000000000..8b16e771b --- /dev/null +++ b/pkg/nsx/services/vpc/wrap.go @@ -0,0 +1,41 @@ +package vpc + +import ( + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func (s *VPCService) WrapHierarchyVPC(org, nsxtProject string, vpc *model.Vpc, lbs *model.LBService) (*model.OrgRoot, error) { + if lbs != nil { + var vpcChildren []*data.StructValue + childrenLBS, err := s.WrapLBS(lbs) + if err != nil { + return nil, err + } + vpcChildren = append(vpcChildren, childrenLBS...) + vpc.Children = vpcChildren + } + var projectChildren []*data.StructValue + childrenVPC, err := s.WrapVPC(vpc) + if err != nil { + return nil, err + } + projectChildren = append(projectChildren, childrenVPC...) + + var orgChildren []*data.StructValue + childrenProject, err := s.WrapProject(nsxtProject, projectChildren) + if err != nil { + return nil, err + } + orgChildren = append(orgChildren, childrenProject...) + + var orgRootChildren []*data.StructValue + childrenOrg, err := s.WrapOrg(org, orgChildren) + if err != nil { + return nil, err + } + orgRootChildren = append(orgRootChildren, childrenOrg...) + + orgRoot, _ := s.WrapOrgRoot(orgRootChildren) + return orgRoot, nil +} diff --git a/pkg/nsx/services/vpc/wrap_test.go b/pkg/nsx/services/vpc/wrap_test.go new file mode 100644 index 000000000..b51338705 --- /dev/null +++ b/pkg/nsx/services/vpc/wrap_test.go @@ -0,0 +1,51 @@ +package vpc + +import ( + "fmt" + "testing" + + "github.com/openlyinc/pointy" + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func TestVPCService_WrapHierarchyVPC(t *testing.T) { + type args struct { + org string + nsxtProject string + vpc *model.Vpc + lbs *model.LBService + } + tests := []struct { + name string + args args + want *model.OrgRoot + wantChildren int + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test", + args: args{ + org: "testorg", + nsxtProject: "testproject", + vpc: &model.Vpc{}, + lbs: &model.LBService{}, + }, + want: &model.OrgRoot{ResourceType: pointy.String("OrgRoot")}, + wantChildren: 1, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &VPCService{} + got, err := s.WrapHierarchyVPC(tt.args.org, tt.args.nsxtProject, tt.args.vpc, tt.args.lbs) + if !tt.wantErr(t, err, fmt.Sprintf("WrapHierarchyVPC(%v, %v, %v, %v)", tt.args.org, tt.args.nsxtProject, tt.args.vpc, tt.args.lbs)) { + return + } + assert.Equalf(t, tt.wantChildren, len(got.Children), "WrapHierarchyVPC children count") + got.Children = nil + assert.Equalf(t, tt.want, got, "WrapHierarchyVPC(%v, %v, %v, %v)", tt.args.org, tt.args.nsxtProject, tt.args.vpc, tt.args.lbs) + }) + } +} diff --git a/pkg/nsx/util/utils.go b/pkg/nsx/util/utils.go index ecae0b5ab..20ef674a1 100644 --- a/pkg/nsx/util/utils.go +++ b/pkg/nsx/util/utils.go @@ -31,7 +31,10 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/logger" ) -var log = logger.Log +var log = &logger.Log + +var HttpCommonError = errors.New("received HTTP Error") +var HttpNotFoundError = errors.New("received HTTP Not Found Error") // ErrorDetail is error detail which info extracted from http.Response.Body. type ErrorDetail struct { @@ -246,7 +249,10 @@ func HandleHTTPResponse(response *http.Response, result interface{}, debug bool) body, err := io.ReadAll(response.Body) defer response.Body.Close() if !(response.StatusCode == http.StatusOK || response.StatusCode == http.StatusAccepted) { - err := errors.New("received HTTP Error") + err := HttpCommonError + if response.StatusCode == http.StatusNotFound { + err = HttpNotFoundError + } log.Error(err, "handle http response", "status", response.StatusCode, "request URL", response.Request.URL, "response body", string(body)) return err, nil } @@ -311,6 +317,63 @@ func DumpHttpRequest(request *http.Request) { log.V(2).Info("http request", "url", request.URL, "body", string(body), "head", request.Header) } +// NSXApiError processes an error and returns a formatted NSX API error message if applicable. +// If the processed API error is nil, return the original error +func NSXApiError(err error) error { + if err == nil { + return err + } + apierror, _ := DumpAPIError(err) + if apierror == nil { + return err + } + return fmt.Errorf("nsx error code: %d, message: %s, details: %s, related error: %s", + safeInt(apierror.ErrorCode), safeString(apierror.ErrorMessage), safeString(apierror.Details), + relatedErrorsToString(apierror.RelatedErrors)) +} + +func relatedErrorToString(err *model.RelatedApiError) string { + if err == nil { + return "nil" + } + + return fmt.Sprintf( + "{Details: %s, ErrorCode: %d, ErrorMessage: %s, ModuleName: %s}", + safeString(err.Details), + safeInt(err.ErrorCode), + safeString(err.ErrorMessage), + safeString(err.ModuleName), + ) +} + +func relatedErrorsToString(errors []model.RelatedApiError) string { + if errors == nil { + return "nil" + } + + var errorStrings []string + for i := 0; i < len(errors); i++ { + currentErr := errors[i] + errorStrings = append(errorStrings, relatedErrorToString(¤tErr)) + } + + return fmt.Sprintf("[%s]", strings.Join(errorStrings, ", ")) +} + +func safeString(ptr *string) string { + if ptr == nil { + return "" + } + return *ptr +} + +func safeInt(ptr *int64) int64 { + if ptr == nil { + return 0 + } + return *ptr +} + // if ApiError is nil, check ErrorTypeEnum, such as ServiceUnavailable // if both return value are nil, the error is not on the list // there is no httpstatus, ApiError does't include it @@ -489,40 +552,16 @@ func FindTag(tags []model.Tag, tagScope string) string { } func CasttoPointer(obj interface{}) interface{} { - switch v := obj.(type) { - case model.Rule: - return &v - case model.StaticRoutes: - return &v - case model.HostTransportNode: - return &v - case model.ClusterControlPlane: - return &v - case model.IpAddressPool: - return &v - case model.GenericPolicyRealizedResource: - return &v - case model.Vpc: - return &v - case model.IpAddressPoolBlockSubnet: - return &v - case model.Group: - return &v - case model.SecurityPolicy: - return &v - case model.Share: - return &v - case model.SegmentPort: - return &v - case model.VpcSubnet: - return &v - case model.VpcSubnetPort: - return &v - case model.IpAddressBlock: - return &v - default: + if obj == nil { return nil } + if reflect.TypeOf(obj).Kind() == reflect.Ptr { + return obj + } + + pointer := reflect.New(reflect.TypeOf(obj)) + pointer.Elem().Set(reflect.ValueOf(obj)) + return pointer.Interface() } func UpdateURL(reqUrl *url.URL, nsxtHost string) { diff --git a/pkg/nsx/util/utils_test.go b/pkg/nsx/util/utils_test.go index 782b6c2f4..a9b0b8d3f 100644 --- a/pkg/nsx/util/utils_test.go +++ b/pkg/nsx/util/utils_test.go @@ -15,10 +15,13 @@ import ( "net/http" "net/http/httptest" "net/url" + "reflect" "strings" "testing" "github.com/stretchr/testify/assert" + mpmodel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" ) func TestHttpErrortoNSXError(t *testing.T) { @@ -510,3 +513,60 @@ Hce3uM6Xn8sAglod/r+0onZ09yoiH2Qj5EY50wUIOPtey2ilhuhwoo/M7Nt/yomF header = CertPemBytesToHeader("/tmp/test.pem") assert.Equal(t, "", header) } + +func TestCasttoPointer(t *testing.T) { + var share *model.Share + Id := "test-id" + principalI := mpmodel.PrincipalIdentity{Id: &Id} + rule := model.Rule{Id: &Id} + tag := model.Tag{Scope: &Id} + lbs := model.LBService{Id: &Id} + share = nil + tests := []struct { + name string + obj interface{} + want interface{} + }{ + + { + name: "PrincipalIdentity", + obj: principalI, + want: &principalI, + }, + { + name: "Rule", + obj: rule, + want: &rule, + }, + // Add more test cases for other types + { + name: "Tag", + obj: tag, + want: &tag, + }, + { + name: "LBService pointer", + obj: &lbs, + want: &lbs, + }, + { + name: "nil", + obj: nil, + want: nil, + }, + + { + name: "typed nil", + obj: share, + want: share, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := CasttoPointer(tt.obj); !reflect.DeepEqual(got, tt.want) { + t.Errorf("CasttoPointer() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/util/cache.go b/pkg/util/cache.go new file mode 100644 index 000000000..e82b97792 --- /dev/null +++ b/pkg/util/cache.go @@ -0,0 +1,4 @@ +package util + +const SubnetPortNamespaceVMIndexKey = "index/SubnetPort/NamespaceVM" +const AddressBindingNamespaceVMIndexKey = "index/AddressBinding/NamespaceVM" diff --git a/pkg/util/retry.go b/pkg/util/retry.go new file mode 100644 index 000000000..131529a0e --- /dev/null +++ b/pkg/util/retry.go @@ -0,0 +1,21 @@ +package util + +import ( + "time" + + "k8s.io/apimachinery/pkg/util/wait" +) + +var NSXTDefaultRetry = wait.Backoff{ + Steps: 10, + Duration: 500 * time.Millisecond, + Factor: 1.0, + Jitter: 0.1, +} + +var NSXTLBVSDefaultRetry = wait.Backoff{ + Steps: 60, + Duration: 500 * time.Millisecond, + Factor: 1.0, + Jitter: 0.1, +} diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 098fd42da..53587d213 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -15,15 +15,17 @@ import ( "github.com/apparentlymart/go-cidr/cidr" mapset "github.com/deckarep/golang-set" + "github.com/google/uuid" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" + t1v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) @@ -44,7 +46,6 @@ var ( common.TagScopeNetworkPolicyName, common.TagScopeNetworkPolicyUID, common.TagScopeSubnetCRName, common.TagScopeSubnetCRUID, common.TagScopeSubnetPortCRName, common.TagScopeSubnetPortCRUID, - common.TagScopeVPCCRName, common.TagScopeVPCCRUID, common.TagScopeIPPoolCRName, common.TagScopeIPPoolCRUID, common.TagScopeSubnetSetCRName, common.TagScopeSubnetSetCRUID, } @@ -57,7 +58,7 @@ func init() { } } -var log = logger.Log +var log = &logger.Log func NormalizeLabels(matchLabels *map[string]string) *map[string]string { newLabels := make(map[string]string) @@ -73,21 +74,30 @@ func NormalizeLabelKey(key string) string { } splitted := strings.Split(key, "/") key = splitted[len(splitted)-1] - return normalizeNamebyLimit(key, common.MaxTagScopeLength) + return normalizeNameByLimit(key, "", common.MaxTagScopeLength) } func NormalizeName(name string) string { - return normalizeNamebyLimit(name, common.MaxTagValueLength) + return normalizeNameByLimit(name, "", common.MaxTagValueLength) } -func normalizeNamebyLimit(name string, limit int) string { - if len(name) <= limit { - return name +func normalizeNameByLimit(name string, suffix string, limit int) string { + newName := connectStrings("-", name, suffix) + if len(newName) <= limit { + return newName + } + + var hashString string + if len(suffix) > 0 { + hashString = Sha1(suffix) + } else { + hashString = Sha1(name) } - hashString := Sha1(name) nameLength := limit - common.HashLength - 1 - newName := fmt.Sprintf("%s-%s", name[:nameLength], hashString[:common.HashLength]) - return newName + if len(name) < nameLength { + nameLength = len(name) + } + return strings.Join([]string{name[:nameLength], hashString[:common.HashLength]}, "-") } func NormalizeId(name string) string { @@ -341,7 +351,7 @@ func GetMapValues(in interface{}) []string { // the changes map contains key/value map that you want to change. // if giving empty value for a key in changes map like: "mykey":"", that means removing this annotation from k8s resource -func UpdateK8sResourceAnnotation(client client.Client, ctx *context.Context, k8sObj client.Object, changes map[string]string) error { +func UpdateK8sResourceAnnotation(client client.Client, ctx context.Context, k8sObj client.Object, changes map[string]string) error { needUpdate := false anno := k8sObj.GetAnnotations() // here it may return a nil because ns do not have annotations. newAnno := If(anno == nil, map[string]string{}, anno).(map[string]string) @@ -366,7 +376,7 @@ func UpdateK8sResourceAnnotation(client client.Client, ctx *context.Context, k8s // only send update request when it is needed if needUpdate { - err := client.Update(*ctx, k8sObj) + err := client.Update(ctx, k8sObj) if err != nil { return err } @@ -374,53 +384,49 @@ func UpdateK8sResourceAnnotation(client client.Client, ctx *context.Context, k8s return nil } -// GenerateID generate id for nsx resource, some resources has complex index, so set it type to string -func GenerateID(res_id, prefix, suffix string, index string) string { - var id strings.Builder - if len(prefix) > 0 { - id.WriteString(prefix) - id.WriteString("_") - } - - id.WriteString(res_id) - if len(index) > 0 { - id.WriteString("_") - id.WriteString(index) +// GenerateIDByObject generate string id for NSX resource using the provided Object's name and uid. Note, +// this function is used on the resources with VPC scenario, and the provided obj is the K8s CR which is +// used to generate the NSX resource. +func GenerateIDByObject(obj metav1.Object) string { + return normalizeNameByLimit(obj.GetName(), string(obj.GetUID()), common.MaxIdLength) +} +// GenerateIDByObjectByLimit generate string id for NSX resource using the provided Object's name and uid, +// and truncate the string with the given limit length. +func GenerateIDByObjectByLimit(obj metav1.Object, limit int) string { + if limit == 0 { + limit = common.MaxIdLength } - if len(suffix) > 0 { - id.WriteString("_") - id.WriteString(suffix) - } - return id.String() + return normalizeNameByLimit(obj.GetName(), string(obj.GetUID()), limit) } -func GenerateDisplayName(res_name, prefix, suffix, project, cluster string) string { - var name strings.Builder - if len(prefix) > 0 { - name.WriteString(prefix) - name.WriteString("-") - } - if len(cluster) > 0 { - name.WriteString(cluster) - name.WriteString("-") +func GenerateIDByObjectWithSuffix(obj metav1.Object, suffix string) string { + limit := common.MaxIdLength + limit -= len(suffix) + 1 + return connectStrings("_", normalizeNameByLimit(obj.GetName(), string(obj.GetUID()), limit), suffix) +} - } - name.WriteString(res_name) - if len(project) > 0 { - name.WriteString("-") - name.WriteString(project) +// GenerateID generate id for NSX resource, some resources has complex index, so set it type to string +func GenerateID(res_id, prefix, suffix string, index string) string { + return connectStrings("_", prefix, res_id, index, suffix) +} +func connectStrings(sep string, parts ...string) string { + strParts := make([]string, 0) + for _, part := range parts { + if len(part) > 0 { + strParts = append(strParts, part) + } } + return strings.Join(strParts, sep) +} - if len(suffix) > 0 { - name.WriteString("-") - name.WriteString(suffix) - } - return name.String() +func GenerateDisplayName(res_name, prefix, suffix, project, cluster string) string { + // Return a string in this format: prefix-cluster-res_name-project-suffix. + return connectStrings("-", prefix, cluster, res_name, project, suffix) } -func GenerateTruncName(limit int, res_name, prefix, suffix, project, cluster string) string { +func GenerateTruncName(limit int, res_name string, prefix, suffix, project, cluster string) string { adjusted_limit := limit - len(prefix) - len(suffix) for _, i := range []string{prefix, suffix} { if len(i) > 0 { @@ -429,8 +435,7 @@ func GenerateTruncName(limit int, res_name, prefix, suffix, project, cluster str } old_name := GenerateDisplayName(res_name, "", "", project, cluster) if len(old_name) > adjusted_limit { - new_name := normalizeNamebyLimit( - old_name, adjusted_limit) + new_name := normalizeNameByLimit(old_name, "", adjusted_limit) return GenerateDisplayName(new_name, prefix, suffix, "", "") } return GenerateDisplayName(res_name, prefix, suffix, project, cluster) @@ -453,7 +458,7 @@ func BuildBasicTags(cluster string, obj interface{}, namespaceID types.UID) []mo tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) tags = append(tags, model.Tag{Scope: String(common.TagScopeStaticRouteCRName), Tag: String(i.ObjectMeta.Name)}) tags = append(tags, model.Tag{Scope: String(common.TagScopeStaticRouteCRUID), Tag: String(string(i.UID))}) - case *v1alpha1.SecurityPolicy: + case *t1v1alpha1.SecurityPolicy: tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) case *networkingv1.NetworkPolicy: tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) @@ -472,14 +477,12 @@ func BuildBasicTags(cluster string, obj interface{}, namespaceID types.UID) []mo tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) tags = append(tags, model.Tag{Scope: String(common.TagScopePodName), Tag: String(i.ObjectMeta.Name)}) tags = append(tags, model.Tag{Scope: String(common.TagScopePodUID), Tag: String(string(i.UID))}) - case *v1alpha1.VPC: + case *v1alpha1.NetworkInfo: tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) - tags = append(tags, model.Tag{Scope: String(common.TagScopeVPCCRName), Tag: String(i.ObjectMeta.Name)}) - tags = append(tags, model.Tag{Scope: String(common.TagScopeVPCCRUID), Tag: String(string(i.UID))}) - case *v1alpha2.IPPool: + case *v1alpha1.IPAddressAllocation: tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) - tags = append(tags, model.Tag{Scope: String(common.TagScopeIPPoolCRName), Tag: String(i.ObjectMeta.Name)}) - tags = append(tags, model.Tag{Scope: String(common.TagScopeIPPoolCRUID), Tag: String(string(i.UID))}) + tags = append(tags, model.Tag{Scope: String(common.TagScopeIPAddressAllocationCRName), Tag: String(i.ObjectMeta.Name)}) + tags = append(tags, model.Tag{Scope: String(common.TagScopeIPAddressAllocationCRUID), Tag: String(string(i.UID))}) default: log.Info("unknown obj type", "obj", obj) } @@ -514,3 +517,8 @@ func Capitalize(s string) string { } return strings.ToUpper(s[:1]) + s[1:] } + +func GetRandomIndexString() string { + uuidStr := uuid.NewString() + return Sha1(uuidStr)[:HashLength] +} diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go index f29b74ac4..638460222 100644 --- a/pkg/util/utils_test.go +++ b/pkg/util/utils_test.go @@ -639,3 +639,71 @@ func Test_calculateOffsetIP(t *testing.T) { }) } } + +func TestGenerateIDByObject(t *testing.T) { + for _, tc := range []struct { + name string + obj metav1.Object + limit int + expID string + }{ + { + name: "no limit set", + obj: &metav1.ObjectMeta{Name: "abcdefg", UID: "b720ee2c-5788-4680-9796-0f93db33d8a9"}, + limit: 0, + expID: "abcdefg-b720ee2c-5788-4680-9796-0f93db33d8a9", + }, + { + name: "truncate with hash on uid", + obj: &metav1.ObjectMeta{Name: "abcdefg", UID: "b720ee2c-5788-4680-9796-0f93db33d8a9"}, + limit: 20, + expID: "abcdefg-df78acb2", + }, + { + name: "longer name with truncate", + obj: &metav1.ObjectMeta{Name: strings.Repeat("a", 256), UID: "b720ee2c-5788-4680-9796-0f93db33d8a9"}, + limit: 0, + expID: fmt.Sprintf("%s-df78acb2", strings.Repeat("a", 246)), + }, + } { + t.Run(tc.name, func(t *testing.T) { + var id string + if tc.limit == 0 { + id = GenerateIDByObject(tc.obj) + } else { + id = GenerateIDByObjectByLimit(tc.obj, tc.limit) + } + assert.Equal(t, tc.expID, id) + }) + } +} + +func TestGenerateIDByObjectWithSuffix(t *testing.T) { + for _, tc := range []struct { + name string + obj metav1.Object + limit int + suffix string + expID string + }{ + { + name: "no limit set", + obj: &metav1.ObjectMeta{Name: "abcdefg", UID: "b720ee2c-5788-4680-9796-0f93db33d8a9"}, + limit: 0, + suffix: "2", + expID: "abcdefg-b720ee2c-5788-4680-9796-0f93db33d8a9_2", + }, + { + name: "longer name with truncate", + obj: &metav1.ObjectMeta{Name: strings.Repeat("a", 256), UID: "b720ee2c-5788-4680-9796-0f93db33d8a9"}, + limit: 0, + suffix: "28e85c0b-21e4-4cab-b1c3-597639dfe752", + expID: fmt.Sprintf("%s-df78acb2_28e85c0b-21e4-4cab-b1c3-597639dfe752", strings.Repeat("a", 209)), + }, + } { + t.Run(tc.name, func(t *testing.T) { + id := GenerateIDByObjectWithSuffix(tc.obj, tc.suffix) + assert.Equal(t, tc.expID, id) + }) + } +} diff --git a/test/e2e/framework.go b/test/e2e/framework.go index a321d135b..5229892eb 100644 --- a/test/e2e/framework.go +++ b/test/e2e/framework.go @@ -6,11 +6,13 @@ import ( "fmt" "log" "net" + "net/url" "os/exec" "regexp" "strings" "time" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,9 +27,8 @@ import ( ) const ( - defaultTimeout = 100 * time.Second - verifyNoneExistTimeout = 15 * time.Second - crdVersion = "v1alpha1" + defaultTimeout = 200 * time.Second + PolicyAPI = "policy/api/v1" ) type Status int @@ -78,7 +79,7 @@ type TestData struct { var testData *TestData -//Temporarily disable traffic check +// Temporarily disable traffic check /* type PodIPs struct { ipv4 *net.IP @@ -339,22 +340,27 @@ func (data *TestData) waitForCRReadyOrDeleted(timeout time.Duration, cr string, return nil } -func (data *TestData) getCRProperties(timeout time.Duration, crType, crName, namespace, key string) (string, error) { +func (data *TestData) getCRPropertiesByJson(timeout time.Duration, crType, crName, namespace, key string) (string, error) { value := "" err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, timeout, false, func(ctx context.Context) (bool, error) { - cmd := fmt.Sprintf("kubectl get %s %s -n %s -o yaml | grep %s", crType, crName, namespace, key) + cmd := "" + // for cluster scope resource, namespace is empty + if namespace == "" { + cmd = fmt.Sprintf("kubectl get %s %s -o json | jq '%s'", crType, crName, key) + } else { + cmd = fmt.Sprintf("kubectl get %s %s -n %s -o json | jq '%s'", crType, crName, namespace, key) + } log.Printf("%s", cmd) rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, cmd) if err != nil || rc != 0 { return false, fmt.Errorf("error when running the following command `%s` on master Node: %v, %s", cmd, err, stdout) } else { - parts := strings.Split(stdout, ":") - if len(parts) != 2 { - return false, fmt.Errorf("failed to read attribute from output %s", stdout) - } else { - value = parts[1] - return true, nil + // check if 'null' in stdout + if strings.Contains(stdout, "null") { + return false, nil } + value = stdout + return true, nil } }) if err != nil { @@ -363,12 +369,18 @@ func (data *TestData) getCRProperties(timeout time.Duration, crType, crName, nam return value, nil } -// Check if CR is created under NS, for resources like VPC, we do not know CR name -// return map structure, key is CR name, value is CR UID -func (data *TestData) getCRResource(timeout time.Duration, cr string, namespace string) (map[string]string, error) { +// For CRs that we do not know the name, return the CR list for upper logic to identify +func (data *TestData) getCRResources(timeout time.Duration, crtype, namespace string) (map[string]string, error) { crs := map[string]string{} err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, timeout, false, func(ctx context.Context) (bool, error) { - cmd := fmt.Sprintf("kubectl get %s -n %s", cr, namespace) + cmd := "" + if namespace == "" { // for cluster scope resources + cmd = fmt.Sprintf("kubectl get %s", crtype) + } else if crtype == "namespaces" { + cmd = fmt.Sprintf("kubectl get %s %s", crtype, namespace) + } else { + cmd = fmt.Sprintf("kubectl get %s -n %s", crtype, namespace) + } log.Printf("%s", cmd) rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, cmd) if err != nil || rc != 0 { @@ -386,7 +398,12 @@ func (data *TestData) getCRResource(timeout time.Duration, cr string, namespace if len(parts) < 1 { // to avoid empty lines continue } - uid_cmd := fmt.Sprintf("kubectl get %s %s -n %s -o yaml | grep uid", cr, parts[0], namespace) + uid_cmd := "" + if namespace == "" || crtype == "namespaces" { + uid_cmd = fmt.Sprintf("kubectl get %s %s -o yaml | grep uid", crtype, parts[0]) + } else { + uid_cmd = fmt.Sprintf("kubectl get %s %s -n %s -o yaml | grep uid", crtype, parts[0], namespace) + } log.Printf("trying to get uid for cr: %s", uid_cmd) rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, uid_cmd) if err != nil || rc != 0 { @@ -404,6 +421,35 @@ func (data *TestData) getCRResource(timeout time.Duration, cr string, namespace return crs, nil } +// Return a singe CR via CR name +func (data *TestData) getCRResource(timeout time.Duration, crtype, crname, namespace string) (string, error) { + ret := "" + err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, timeout, false, func(ctx context.Context) (bool, error) { + // If namespace is empty, then this is a cluster scope resource. + uid_cmd := "" + if namespace == "" { + uid_cmd = fmt.Sprintf("kubectl get %s %s -o yaml | grep uid", crtype, crname) + } else if crtype == "namespaces" { + uid_cmd = fmt.Sprintf("kubectl get %s %s -o yaml | grep uid", crtype, namespace) + } else { + uid_cmd = fmt.Sprintf("kubectl get %s %s -n %s -o yaml | grep uid", crtype, crname, namespace) + } + log.Printf("%s", uid_cmd) + rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, uid_cmd) + if err != nil || rc != 0 { + return false, fmt.Errorf("error when running the following command `%s` on master Node: %v, %s", uid_cmd, err, stdout) + } else { + uid := strings.Split(stdout, ":")[1] + ret = uid + } + return true, nil + }) + if err != nil { + return "", err + } + return ret, nil +} + // deploymentWaitForNames polls the K8s apiServer once the specific pods are created, no matter they are running or not. func (data *TestData) deploymentWaitForNames(timeout time.Duration, namespace, deployment string) ([]string, error) { var podNames []string @@ -429,7 +475,7 @@ func (data *TestData) deploymentWaitForNames(timeout time.Duration, namespace, d return podNames, nil } -//Temporarily disable traffic check +// Temporarily disable traffic check /* // podWaitFor polls the K8s apiServer until the specified Pod is found (in the test Namespace) and // the condition predicate is met (or until the provided timeout expires). @@ -642,7 +688,7 @@ func applyYAML(filename string, ns string) error { return nil } -//Temporarily disable traffic check +// Temporarily disable traffic check /* func runCommand(cmd string) (string, error) { err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, defaultTimeout, false, func(ctx context.Context) (bool, error) { @@ -687,6 +733,32 @@ func deleteYAML(filename string, ns string) error { return nil } +// queryResource is used to query resource by tags, not handling pagination +// tags should be present in pairs, the first tag is the scope, the second tag is the value +// caller should transform the response to the expected resource type +func (data *TestData) queryResource(resourceType string, tags []string) (model.SearchResponse, error) { + tagScopeClusterKey := strings.Replace(common.TagScopeNamespace, "/", "\\/", -1) + tagScopeClusterValue := strings.Replace(tags[0], ":", "\\:", -1) + tagParam := fmt.Sprintf("tags.scope:%s AND tags.tag:%s", tagScopeClusterKey, tagScopeClusterValue) + resourceParam := fmt.Sprintf("%s:%s", common.ResourceType, resourceType) + queryParam := resourceParam + " AND " + tagParam + if len(tags) >= 2 { + tagscope := strings.Replace(tags[0], "/", "\\/", -1) + tagtag := strings.Replace(tags[1], ":", "\\:", -1) + tagParam = fmt.Sprintf("tags.scope:%s AND tags.tag:%s", tagscope, tagtag) + queryParam = resourceParam + " AND " + tagParam + } + queryParam += " AND marked_for_delete:false" + var cursor *string + var pageSize int64 = 500 + response, err := data.nsxClient.QueryClient.List(queryParam, cursor, nil, &pageSize, nil, nil) + if err != nil { + log.Printf("Error when querying resource %s: %v", resourceType, err) + return model.SearchResponse{}, err + } + return response, nil +} + func (data *TestData) waitForResourceExist(namespace string, resourceType string, key string, value string, shouldExist bool) error { err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, defaultTimeout, false, func(ctx context.Context) (bool, error) { exist := true @@ -716,10 +788,39 @@ func (data *TestData) waitForResourceExist(namespace string, resourceType string return err } -func (data *TestData) waitForResourceExistById(namespace string, resourceType string, id string, shouldExist bool) error { - return data.waitForResourceExist(namespace, resourceType, "id", id, shouldExist) -} - func (data *TestData) waitForResourceExistOrNot(namespace string, resourceType string, resourceName string, shouldExist bool) error { return data.waitForResourceExist(namespace, resourceType, "display_name", resourceName, shouldExist) } + +func (data *TestData) waitForResourceExistByPath(pathPolicy string, shouldExist bool) error { + err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, defaultTimeout, false, func(ctx context.Context) (bool, error) { + exist := true + + fullURL := PolicyAPI + pathPolicy + fullURL = strings.ReplaceAll(fullURL, "\"", "") + fullURL = strings.ReplaceAll(fullURL, "\n", "") + fullURL = strings.ReplaceAll(fullURL, "\r", "") + _, err := url.Parse(fullURL) + if err != nil { + fmt.Println("Invalid URL:", err) + return false, err + } + + resp, err := testData.nsxClient.Client.Cluster.HttpGet(fullURL) + if err != nil { + if !shouldExist { + return true, nil + } + return false, err + } + id, ok := resp["id"].(string) + if !ok || id == "" { + exist = false + } + if exist != shouldExist { + return false, nil + } + return true, nil + }) + return err +} diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index a849f68dd..2152ff6a6 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -8,39 +8,11 @@ import ( "log" "os" "testing" -) -// setupLogging creates a temporary directory to export the test logs if necessary. If a directory -// was provided by the user, it checks that the directory exists. -func (tOptions *TestOptions) setupLogging() func() { - if tOptions.logsExportDir == "" { - name, err := os.MkdirTemp("", "nsx-operator-e2e-test-") - if err != nil { - log.Fatalf("Error when creating temporary directory to export logs: %v", err) - } - log.Printf("Test logs (if any) will be exported under the '%s' directory", name) - tOptions.logsExportDir = name - // we will delete the temporary directory if no logs are exported - return func() { - if empty, _ := IsDirEmpty(name); empty { - log.Printf("Removing empty logs directory '%s'", name) - _ = os.Remove(name) - } else { - log.Printf("Logs exported under '%s', it is your responsibility to delete the directory when you no longer need it", name) - } - } - } else { - fInfo, err := os.Stat(tOptions.logsExportDir) - if err != nil { - log.Fatalf("Cannot stat provided directory '%s': %v", tOptions.logsExportDir, err) - } - if !fInfo.Mode().IsDir() { - log.Fatalf("'%s' is not a valid directory", tOptions.logsExportDir) - } - } - // no-op cleanup function - return func() {} -} + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/vmware-tanzu/nsx-operator/pkg/logger" +) // testMain is meant to be called by TestMain and enables the use of defer statements. func testMain(m *testing.M) int { @@ -52,13 +24,12 @@ func testMain(m *testing.M) int { flag.BoolVar(&testOptions.withIPPool, "ippool", false, "Run tests include IPPool tests") flag.Parse() + logf.SetLogger(logger.ZapLogger(true, 2)) + if err := initProvider(); err != nil { log.Fatalf("Error when initializing provider: %v", err) } - cleanupLogging := testOptions.setupLogging() - defer cleanupLogging() - log.Println("Creating clientSets") if err := NewTestData(testOptions.operatorConfigPath); err != nil { diff --git a/test/e2e/manifest/testIPPool/ippool.yaml b/test/e2e/manifest/testIPPool/ippool.yaml index ee471552f..dccbba996 100644 --- a/test/e2e/manifest/testIPPool/ippool.yaml +++ b/test/e2e/manifest/testIPPool/ippool.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha2 +apiVersion: crd.nsx.vmware.com/v1alpha2 kind: IPPool metadata: name: guestcluster-ippool-2 diff --git a/test/e2e/manifest/testIPPool/ippool_delete.yaml b/test/e2e/manifest/testIPPool/ippool_delete.yaml index fcacf0b46..d80bac6d0 100644 --- a/test/e2e/manifest/testIPPool/ippool_delete.yaml +++ b/test/e2e/manifest/testIPPool/ippool_delete.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha2 +apiVersion: crd.nsx.vmware.com/v1alpha2 kind: IPPool metadata: name: guestcluster-ippool-2 diff --git a/test/e2e/manifest/testIPPool/ippool_subnet_nil.yaml b/test/e2e/manifest/testIPPool/ippool_subnet_nil.yaml index 343f4cc22..408964e2b 100644 --- a/test/e2e/manifest/testIPPool/ippool_subnet_nil.yaml +++ b/test/e2e/manifest/testIPPool/ippool_subnet_nil.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha2 +apiVersion: crd.nsx.vmware.com/v1alpha2 kind: IPPool metadata: name: guestcluster-ippool-2 diff --git a/test/e2e/manifest/testSecurityPolicy/match-expression.yaml b/test/e2e/manifest/testSecurityPolicy/match-expression.yaml index 578641751..2e9e00359 100644 --- a/test/e2e/manifest/testSecurityPolicy/match-expression.yaml +++ b/test/e2e/manifest/testSecurityPolicy/match-expression.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: expression-policy-1 diff --git a/test/e2e/manifest/testSecurityPolicy/named-port-without-pod.yaml b/test/e2e/manifest/testSecurityPolicy/named-port-without-pod.yaml index 6d5a18d66..b2377f8b5 100644 --- a/test/e2e/manifest/testSecurityPolicy/named-port-without-pod.yaml +++ b/test/e2e/manifest/testSecurityPolicy/named-port-without-pod.yaml @@ -27,7 +27,7 @@ spec: cpu: "10000m" memory: "10000Gi" --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy-without-pod diff --git a/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy-1.yaml b/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy-1.yaml index a98cb36dd..15240c57a 100644 --- a/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy-1.yaml +++ b/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy-1.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: isolate-policy-1 diff --git a/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy.yaml b/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy.yaml index dd10d1518..64d5a23d9 100644 --- a/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy.yaml +++ b/test/e2e/manifest/testSecurityPolicy/ns-isolation-policy.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: isolate-policy-1 diff --git a/test/e2e/manifest/testSecurityPolicy/rule-in-policy-applied-to.yaml b/test/e2e/manifest/testSecurityPolicy/rule-in-policy-applied-to.yaml index 612d13042..1f0bed60a 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-in-policy-applied-to.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-in-policy-applied-to.yaml @@ -39,7 +39,7 @@ spec: - containerPort: 80 name: web-port --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to-with-src.yaml b/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to-with-src.yaml index 52c6e61e2..166bdd10e 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to-with-src.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to-with-src.yaml @@ -41,7 +41,7 @@ spec: - containerPort: 80 name: web-port --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to.yaml b/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to.yaml index 3aca184b1..c21ada47e 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-in-rule-applied-to.yaml @@ -39,7 +39,7 @@ spec: - containerPort: 80 name: web-port --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-out-policy-applied-to-with-dst.yaml b/test/e2e/manifest/testSecurityPolicy/rule-out-policy-applied-to-with-dst.yaml index 4a971a579..a94e8e099 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-out-policy-applied-to-with-dst.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-out-policy-applied-to-with-dst.yaml @@ -49,7 +49,7 @@ spec: command: ["nc", "-l", "-p", "1234"] imagePullPolicy: IfNotPresent --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port-multi.yaml b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port-multi.yaml index a22045ff9..a91c44be5 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port-multi.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port-multi.yaml @@ -81,7 +81,7 @@ spec: name: web imagePullPolicy: IfNotPresent --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port.yaml b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port.yaml index 44ef9bb89..f111480a8 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst-with-dup-port.yaml @@ -79,7 +79,7 @@ spec: - containerPort: 80 name: web-port --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst.yaml b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst.yaml index b1af7eb49..db9752d02 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-dst.yaml @@ -53,7 +53,7 @@ spec: command: ["nc", "-l", "-p", "1234"] imagePullPolicy: IfNotPresent --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-expression-selector.yaml b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-expression-selector.yaml index 3193b6c22..7f27ff796 100644 --- a/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-expression-selector.yaml +++ b/test/e2e/manifest/testSecurityPolicy/rule-out-rule-applied-to-with-expression-selector.yaml @@ -80,7 +80,7 @@ spec: command: ["nc", "-l", "-p", "4321"] imagePullPolicy: IfNotPresent --- -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SecurityPolicy metadata: name: named-port-policy diff --git a/test/e2e/manifest/testSubnet/shared_ns.yaml b/test/e2e/manifest/testSubnet/shared_ns.yaml index 6f3f2122f..fdcee065c 100644 --- a/test/e2e/manifest/testSubnet/shared_ns.yaml +++ b/test/e2e/manifest/testSubnet/shared_ns.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Namespace metadata: annotations: - nsx.vmware.com/vpc_name: target-ns/target-ns-vpc + nsx.vmware.com/shared_vpc_namespace: target-ns name: target-ns --- @@ -11,5 +11,5 @@ apiVersion: v1 kind: Namespace metadata: annotations: - nsx.vmware.com/vpc_name: target-ns/target-ns-vpc + nsx.vmware.com/shared_vpc_namespace: target-ns name: subnet-e2e-shared diff --git a/test/e2e/manifest/testSubnet/subnetport-in-dhcp-subnetset.yaml b/test/e2e/manifest/testSubnet/subnetport-in-dhcp-subnetset.yaml index fb792f3dc..286082d4a 100644 --- a/test/e2e/manifest/testSubnet/subnetport-in-dhcp-subnetset.yaml +++ b/test/e2e/manifest/testSubnet/subnetport-in-dhcp-subnetset.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetPort metadata: name: port-in-dhcp-subnetset diff --git a/test/e2e/manifest/testSubnet/subnetport-in-static-subnetset.yaml b/test/e2e/manifest/testSubnet/subnetport-in-static-subnetset.yaml index f7ff4e656..e48f1b83b 100644 --- a/test/e2e/manifest/testSubnet/subnetport-in-static-subnetset.yaml +++ b/test/e2e/manifest/testSubnet/subnetport-in-static-subnetset.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetPort metadata: name: port-in-static-subnetset diff --git a/test/e2e/manifest/testSubnet/subnetport_1.yaml b/test/e2e/manifest/testSubnet/subnetport_1.yaml index 39a837258..99d8491b4 100644 --- a/test/e2e/manifest/testSubnet/subnetport_1.yaml +++ b/test/e2e/manifest/testSubnet/subnetport_1.yaml @@ -1,7 +1,7 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetPort metadata: - name: port-1 + name: port-e2e-test-1 namespace: subnet-e2e spec: subnetSet: pod-default diff --git a/test/e2e/manifest/testSubnet/subnetport_3.yaml b/test/e2e/manifest/testSubnet/subnetport_3.yaml index c4f258467..b4de8d2e5 100644 --- a/test/e2e/manifest/testSubnet/subnetport_3.yaml +++ b/test/e2e/manifest/testSubnet/subnetport_3.yaml @@ -1,6 +1,6 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetPort metadata: - name: port-3 + name: port-e2e-test-3 namespace: subnet-e2e-shared spec: diff --git a/test/e2e/manifest/testSubnet/subnetset-dhcp.yaml b/test/e2e/manifest/testSubnet/subnetset-dhcp.yaml index 5ad93acdb..7a5e12ab8 100644 --- a/test/e2e/manifest/testSubnet/subnetset-dhcp.yaml +++ b/test/e2e/manifest/testSubnet/subnetset-dhcp.yaml @@ -1,8 +1,9 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetSet metadata: name: user-pod-subnetset-dhcp namespace: subnet-e2e spec: + accessMode: PrivateTGW DHCPConfig: enableDHCP: true diff --git a/test/e2e/manifest/testSubnet/subnetset-static.yaml b/test/e2e/manifest/testSubnet/subnetset-static.yaml index 779d15431..8e6945f60 100644 --- a/test/e2e/manifest/testSubnet/subnetset-static.yaml +++ b/test/e2e/manifest/testSubnet/subnetset-static.yaml @@ -1,9 +1,7 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetSet metadata: name: user-pod-subnetset-static namespace: subnet-e2e spec: - advancedConfig: - staticIPAllocation: - enable: true + accessMode: Private diff --git a/test/e2e/manifest/testSubnetPort/port_with_attachment_ref.yaml b/test/e2e/manifest/testSubnetPort/port_with_attachment_ref.yaml index c798e4055..dd1871b2d 100644 --- a/test/e2e/manifest/testSubnetPort/port_with_attachment_ref.yaml +++ b/test/e2e/manifest/testSubnetPort/port_with_attachment_ref.yaml @@ -1,4 +1,4 @@ -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: SubnetPort metadata: name: vm-port diff --git a/test/e2e/manifest/testVPC/customize_networkconfig.yaml b/test/e2e/manifest/testVPC/customize_networkconfig.yaml index 913c8e46d..4b2c6ecea 100644 --- a/test/e2e/manifest/testVPC/customize_networkconfig.yaml +++ b/test/e2e/manifest/testVPC/customize_networkconfig.yaml @@ -1,19 +1,13 @@ # This file is used in testing customized VPC case, # it support customer to define its own VPC network config. -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: VPCNetworkConfiguration metadata: name: selfdefinedconfig spec: - defaultGatewayPath: /infra/tier-0s/PLR - # nsx-operator-ci would replace '{edge-cluster-id}' with real edge-cluster-id of testbed - edgeClusterPath: /infra/sites/default/enforcement-points/default/edge-clusters/{edge-cluster-id} - defaultIPv4SubnetSize: 26 - nsxtProject: /orgs/default/projects/nsx_operator_e2e_test - externalIPv4Blocks: - - /infra/ip-blocks/e2e_test_external_ip_blk - privateIPv4CIDRs: + defaultSubnetSize: 32 + nsxProject: /orgs/default/projects/nsx_operator_e2e_test + privateIPs: - 172.29.0.0/16 - 172.39.0.0/16 - defaultSubnetAccessMode: Public - \ No newline at end of file + vpcConnectivityProfile: /orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default diff --git a/test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml b/test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml new file mode 100644 index 000000000..295759785 --- /dev/null +++ b/test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml @@ -0,0 +1,14 @@ +# This file is used in testing customized VPC case, +# it support customer to define its own VPC network config. +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: VPCNetworkConfiguration +metadata: + name: selfdefinedconfig +spec: + defaultSubnetSize: 32 + nsxProject: /orgs/default/projects/nsx_operator_e2e_test + privateIPs: + - 172.29.0.0/16 + - 172.39.0.0/16 + - 172.49.0.0/16 + vpcConnectivityProfile: /orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default diff --git a/test/e2e/manifest/testVPC/default_networkconfig.yaml b/test/e2e/manifest/testVPC/default_networkconfig.yaml index dbfb2edb3..1ca5b3d3c 100644 --- a/test/e2e/manifest/testVPC/default_networkconfig.yaml +++ b/test/e2e/manifest/testVPC/default_networkconfig.yaml @@ -2,21 +2,16 @@ # it should be applied on testbed setup stage, # any new created namespace that do not have networkconfig specified on annotations # will use this network config by default -apiVersion: nsx.vmware.com/v1alpha1 +apiVersion: crd.nsx.vmware.com/v1alpha1 kind: VPCNetworkConfiguration metadata: name: default annotations: nsx.vmware.com/default: "true" spec: - defaultGatewayPath: /infra/tier-0s/PLR - # nsx-operator-ci would replace '{edge-cluster-id}' with real edge-cluster-id of testbed - edgeClusterPath: /infra/sites/default/enforcement-points/default/edge-clusters/{edge-cluster-id} - defaultIPv4SubnetSize: 26 - nsxtProject: /orgs/default/projects/nsx_operator_e2e_test - externalIPv4Blocks: - - /infra/ip-blocks/e2e_test_external_ip_blk - privateIPv4CIDRs: + defaultSubnetSize: 32 + nsxProject: /orgs/default/projects/nsx_operator_e2e_test + privateIPs: - 172.28.0.0/16 - 172.38.0.0/16 - defaultSubnetAccessMode: Public + vpcConnectivityProfile: /orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default diff --git a/test/e2e/manifest/testVPC/infra_networkconfig.yaml b/test/e2e/manifest/testVPC/infra_networkconfig.yaml deleted file mode 100644 index c6af88743..000000000 --- a/test/e2e/manifest/testVPC/infra_networkconfig.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# This file is used in testing VPC case, -# it should be applied on testbed setup stage, -# for infra namespaces, they should use this network config. -apiVersion: nsx.vmware.com/v1alpha1 -kind: VPCNetworkConfiguration -metadata: - name: infra -spec: - defaultGatewayPath: /infra/tier-0s/PLR - # nsx-operator-ci would replace '{edge-cluster-id}' with real edge-cluster-id of testbed - edgeClusterPath: /infra/sites/default/enforcement-points/default/edge-clusters/{edge-cluster-id} - defaultIPv4SubnetSize: 26 - nsxtProject: /orgs/default/projects/nsx_operator_e2e_test - externalIPv4Blocks: - - /infra/ip-blocks/e2e_test_external_ip_blk - privateIPv4CIDRs: - - 172.27.0.0/16 - - 172.37.0.0/16 - defaultSubnetAccessMode: Public - \ No newline at end of file diff --git a/test/e2e/manifest/testVPC/shared_ns.yaml b/test/e2e/manifest/testVPC/shared_ns.yaml new file mode 100644 index 000000000..c653e0acd --- /dev/null +++ b/test/e2e/manifest/testVPC/shared_ns.yaml @@ -0,0 +1,17 @@ +# This file is used in testing shared VPC case, +# it create a namespace with customized network config for VPC. +apiVersion: v1 +kind: Namespace +metadata: + annotations: + nsx.vmware.com/vpc_network_config: selfdefinedconfig + name: shared-vpc-ns-0 + +--- +apiVersion: v1 +kind: Namespace +metadata: + annotations: + nsx.vmware.com/vpc_network_config: selfdefinedconfig + nsx.vmware.com/shared_vpc_namespace: shared-vpc-ns-0 + name: shared-vpc-ns-1 diff --git a/test/e2e/manifest/testVPC/system_networkconfig.yaml b/test/e2e/manifest/testVPC/system_networkconfig.yaml new file mode 100644 index 000000000..3660f723e --- /dev/null +++ b/test/e2e/manifest/testVPC/system_networkconfig.yaml @@ -0,0 +1,14 @@ +# This file is used in testing VPC case, +# it should be applied on testbed setup stage, +# for system namespaces, they should use this network config. +apiVersion: crd.nsx.vmware.com/v1alpha1 +kind: VPCNetworkConfiguration +metadata: + name: system +spec: + defaultSubnetSize: 32 + nsxProject: /orgs/default/projects/nsx_operator_e2e_test + privateIPs: + - 172.27.0.0/16 + - 172.37.0.0/16 + vpcConnectivityProfile: /orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default diff --git a/test/e2e/manifest/testVPC/update_ns.yaml b/test/e2e/manifest/testVPC/update_ns.yaml new file mode 100644 index 000000000..fe2bccd36 --- /dev/null +++ b/test/e2e/manifest/testVPC/update_ns.yaml @@ -0,0 +1,8 @@ +# This file is used in testing shared VPC case, +# it create a namespace with customized network config for VPC. +apiVersion: v1 +kind: Namespace +metadata: + annotations: + nsx.vmware.com/vpc_network_config: selfdefinedconfig + name: update-ns \ No newline at end of file diff --git a/test/e2e/nsx_ippool_test.go b/test/e2e/nsx_ippool_test.go deleted file mode 100644 index cc5f837bc..000000000 --- a/test/e2e/nsx_ippool_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// This file is for e2e ippool tests. - -package e2e - -import ( - "path/filepath" - "testing" - - "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" -) - -const ( - IPPool = "ippool" -) - -// TestIPPoolBasic verifies that it could successfully realize ippool subnet from ipblock. -func TestIPPoolBasic(t *testing.T) { - ns := "sc-a" - name := "guestcluster-ippool-2" - subnet_name_1 := "guestcluster1-workers-a" - subnet_name_2 := "guestcluster1-workers-b" - subnet_name_3 := "guestcluster1-workers-c" - setupTest(t, ns) - defer teardownTest(t, ns, defaultTimeout) - - // Create ippool - ippoolPath, _ := filepath.Abs("./manifest/testIPPool/ippool.yaml") - _ = applyYAML(ippoolPath, ns) - defer deleteYAML(ippoolPath, ns) - - // Check ippool status - err := testData.waitForCRReadyOrDeleted(defaultTimeout, IPPool, ns, name, Ready) - assertNil(t, err, "Error when waiting for IPPool %s", name) - - // Check nsx-t resource existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_1, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_2, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_3, true) - assertNil(t, err) - - // Delete ippool - _ = deleteYAML(ippoolPath, ns) - - // Check nsx-t resource not existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, false) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_1, false) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_2, false) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_3, false) - assertNil(t, err) -} - -// TestIPPoolAddDeleteSubnet verifies that it is as expected when adding or deleting some subnets. -func TestIPPoolAddDeleteSubnet(t *testing.T) { - ns := "sc-a" - name := "guestcluster-ippool-2" - subnet_name_1 := "guestcluster1-workers-a" - subnet_name_2 := "guestcluster1-workers-b" - subnet_name_3 := "guestcluster1-workers-c" - setupTest(t, ns) - defer teardownTest(t, ns, defaultTimeout) - - // Create ippool - ippoolPath, _ := filepath.Abs("./manifest/testIPPool/ippool.yaml") - _ = applyYAML(ippoolPath, ns) - defer deleteYAML(ippoolPath, ns) - - // Check ippool status - err := testData.waitForCRReadyOrDeleted(defaultTimeout, IPPool, ns, name, Ready) - assertNil(t, err, "Error when waiting for IPPool %s", name) - - // Check nsx-t resource existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_1, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_2, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_3, true) - assertNil(t, err) - - // Delete subnet_name_2 and subnet_name_3 - ippoolDeletePath, _ := filepath.Abs("./manifest/testIPPool/ippool_delete.yaml") - _ = applyYAML(ippoolDeletePath, ns) - - // Check ippool status - err = testData.waitForCRReadyOrDeleted(defaultTimeout, IPPool, ns, name, Ready) - assertNil(t, err, "Error when waiting for IPPool %s", name) - - // Check nsx-t resource existing and not existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, true) - assertNil(t, err) - // Still existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_1, true) - assertNil(t, err) - // Deleted - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_2, false) - assertNil(t, err) - // Deleted - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_3, false) - assertNil(t, err) - - // Add back subnet_name_2 and subnet_name_3 - _ = applyYAML(ippoolPath, ns) - // Check ippool status - err = testData.waitForCRReadyOrDeleted(defaultTimeout, IPPool, ns, name, Ready) - assertNil(t, err, "Error when waiting for IPPool %s", name) - - // Check nsx-t resource existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_1, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_2, true) - assertNil(t, err) - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPoolBlockSubnet, subnet_name_3, true) - assertNil(t, err) -} - -// TestIPPoolBasic verifies that it could support when subnets are nil -func TestIPPoolSubnetsNil(t *testing.T) { - ns := "sc-a" - name := "guestcluster-ippool-2" - setupTest(t, ns) - defer teardownTest(t, ns, defaultTimeout) - - // Create ippool - ippoolPath, _ := filepath.Abs("./manifest/testIPPool/ippool.yaml") - _ = applyYAML(ippoolPath, ns) - defer deleteYAML(ippoolPath, ns) - - // Check ippool status - err := testData.waitForCRReadyOrDeleted(defaultTimeout, IPPool, ns, name, Ready) - assertNil(t, err, "Error when waiting for IPPool %s", name) - - // Check nsx-t resource existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, true) - assertNil(t, err) - - // Delete ippool - _ = deleteYAML(ippoolPath, ns) - - // Check nsx-t resource not existing - err = testData.waitForResourceExistOrNot(ns, common.ResourceTypeIPPool, name, false) - assertNil(t, err) -} diff --git a/test/e2e/nsx_networkinfo_test.go b/test/e2e/nsx_networkinfo_test.go new file mode 100644 index 000000000..8e0358329 --- /dev/null +++ b/test/e2e/nsx_networkinfo_test.go @@ -0,0 +1,194 @@ +package e2e + +import ( + "log" + "path/filepath" + "strings" + "testing" +) + +const ( + NetworkInfoCRType = "networkinfos.crd.nsx.vmware.com" + NetworkConfigCRType = "vpcnetworkconfigurations.crd.nsx.vmware.com" + NSCRType = "namespaces" + PrivateIPBlockNSXType = "IpAddressBlock" + + TestCustomizedNetworkConfigName = "selfdefinedconfig" + TestInfraNetworkConfigName = "system" + TestDefaultNetworkConfigName = "default" + + InfraVPCNamespace = "kube-system" + SharedInfraVPCNamespace = "kube-public" + + CustomizedPrivateCIDR1 = "172.29.0.0" + CustomizedPrivateCIDR2 = "172.39.0.0" + CustomizedPrivateCIDR3 = "172.39.0.0" +) + +func verifyCRCreated(t *testing.T, crtype string, ns string, crname string, expect int) (string, string) { + // For CRs that do not know the name, get all resources and compare with expected + if crname == "" { + // get CR list with CR type + resources, err := testData.getCRResources(defaultTimeout, crtype, ns) + // CR list lengh should match expected length + assertNil(t, err) + if len(resources) != expect { + log.Printf("%s list %s size not the same as expected %d", crtype, resources, expect) + panic("CR creation verify failed") + } + + // TODO: if mutiple resources are required, here we need to return multiple elements, but for now, we only need one. + cr_name, cr_uid := "", "" + for k, v := range resources { + cr_name = k + cr_uid = strings.TrimSpace(v) + } + return cr_name, cr_uid + } else { + // there should be one networkinfo created + uid, err := testData.getCRResource(defaultTimeout, crtype, crname, ns) + assertNil(t, err) + + return crname, strings.TrimSpace(uid) + } +} + +func verifyCRDeleted(t *testing.T, crtype string, ns string) { + res, _ := testData.getCRResources(defaultTimeout, crtype, ns) + assertTrue(t, len(res) == 0, "NetworkInfo CR %s should be deleted", crtype) +} + +// Test Customized NetworkInfo +func TestCustomizedNetworkInfo(t *testing.T) { + // Create customized networkconfig + ncPath, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig.yaml") + _ = applyYAML(ncPath, "") + nsPath, _ := filepath.Abs("./manifest/testVPC/customize_ns.yaml") + _ = applyYAML(nsPath, "") + + defer deleteYAML(nsPath, "") + defer deleteYAML(ncPath, "") + + ns := "customized-ns" + + // For networkinfo CR, its CR name is the same as namespace + verifyCRCreated(t, NetworkInfoCRType, ns, ns, 1) + verifyCRCreated(t, NSCRType, ns, ns, 1) + + vpcPath, _ := testData.getCRPropertiesByJson( + defaultTimeout, NetworkConfigCRType, TestCustomizedNetworkConfigName, "", ".status.vpcs[0].vpcPath") + err := testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) +} + +// Test Infra NetworkInfo +func TestInfraNetworkInfo(t *testing.T) { + // Check namespace cr existence + verifyCRCreated(t, NSCRType, InfraVPCNamespace, InfraVPCNamespace, 1) + + // Check networkinfo cr existence + verifyCRCreated(t, NetworkInfoCRType, InfraVPCNamespace, InfraVPCNamespace, 1) + + vpcPath, _ := testData.getCRPropertiesByJson( + defaultTimeout, NetworkConfigCRType, TestInfraNetworkConfigName, "", ".status.vpcs[0].vpcPath") + err := testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) + + // kube-public namespace should have its own NetworkInfo CR + // Check networkinfo cr existence + verifyCRCreated(t, NetworkInfoCRType, SharedInfraVPCNamespace, SharedInfraVPCNamespace, 1) +} + +// Test Default NetworkInfo +func TestDefaultNetworkInfo(t *testing.T) { + // If no annotation on namespace, then NetworkInfo will use default network config to create vpc under each ns + ns := "networkinfo-default-1" + setupTest(t, ns) + defer teardownTest(t, ns, defaultTimeout) + + // Check namespace cr existence + verifyCRCreated(t, NSCRType, ns, ns, 1) + + // Check networkinfo cr existence + verifyCRCreated(t, NetworkInfoCRType, ns, ns, 1) + + // TODO: for default network config, it maybe shared by multiple ns, and the vpc[0] may not be its VPC + // in WCP scenario, there will be no shared network config, skip this part, leave for future if we need to + // support non-WCP scenarios. + // vpcPath, _ := testData.getCRPropertiesByJson( + // defaultTimeout, NetworkConfigCRType, TestDefaultNetworkConfigName, "", ".status.vpcs[0].vpcPath") + // err := testData.waitForResourceExistByPath(vpcPath, true) + // assertNil(t, err) + + // delete namespace and check all resources are deleted + // normally, when deleting ns, if using shared vpc, then no vpc will be deleted + // if using normal vpc, in ns deletion, the networkconfig CR will also be deleted, so there is no + // need to check vpcPath deletion on network config CR anymore + err := testData.deleteNamespace(ns, defaultTimeout) + assertNil(t, err) + verifyCRDeleted(t, NetworkInfoCRType, ns) + verifyCRDeleted(t, NSCRType, ns) + // err = testData.waitForResourceExistByPath(vpcPath, false) + assertNil(t, err) +} + +// ns1 share vpc with ns, each ns should have its own NetworkInfo +// delete ns1, vpc should not be deleted +func TestSharedNSXVPC(t *testing.T) { + ns := "shared-vpc-ns-0" + ns1 := "shared-vpc-ns-1" + + nsPath, _ := filepath.Abs("./manifest/testVPC/shared_ns.yaml") + _ = applyYAML(nsPath, "") + defer deleteYAML(nsPath, "") + + // Check namespace cr existence + verifyCRCreated(t, NSCRType, ns, ns, 1) + verifyCRCreated(t, NSCRType, ns1, ns1, 1) + + // Check networkinfo cr existence + verifyCRCreated(t, NetworkInfoCRType, ns, ns, 1) + verifyCRCreated(t, NetworkInfoCRType, ns1, ns1, 1) + + vpcPath, err := testData.getCRPropertiesByJson( + defaultTimeout, NetworkConfigCRType, TestCustomizedNetworkConfigName, "", ".status.vpcs[0].vpcPath") + assertNil(t, err) + + // delete ns1 and check vpc not deleted + err = testData.deleteNamespace(ns1, defaultTimeout) + assertNil(t, err) + verifyCRDeleted(t, NetworkInfoCRType, ns1) + verifyCRDeleted(t, NSCRType, ns1) + err = testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) +} + +// update vpcnetworkconfig, and check vpc is updated +func TestUpdateVPCNetworkconfigNetworkInfo(t *testing.T) { + ns := "update-ns" + + nsPath, _ := filepath.Abs("./manifest/testVPC/update_ns.yaml") + _ = applyYAML(nsPath, "") + defer deleteYAML(nsPath, "") + + vncPathOriginal, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig.yaml") + defer applyYAML(vncPathOriginal, "") + + // Check namespace cr existence + verifyCRCreated(t, NSCRType, ns, ns, 1) + + // Check networkinfo cr existence + networkinfo_name, _ := verifyCRCreated(t, NetworkInfoCRType, ns, ns, 1) + + privateIPs, err := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].privateIPs") + assertTrue(t, strings.Contains(privateIPs, CustomizedPrivateCIDR1), "privateIPs %s should contain %s", privateIPs, CustomizedPrivateCIDR1) + assertTrue(t, strings.Contains(privateIPs, CustomizedPrivateCIDR2), "privateIPs %s should contain %s", privateIPs, CustomizedPrivateCIDR1) + assertNil(t, err) + + vncPath, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig_updated.yaml") + _ = applyYAML(vncPath, "") + + privateIPs, err = testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].privateIPs") + assertTrue(t, strings.Contains(privateIPs, CustomizedPrivateCIDR3), "privateIPs %s should contain %s", privateIPs, CustomizedPrivateCIDR3) + assertNil(t, err) +} diff --git a/test/e2e/nsx_security_policy_test.go b/test/e2e/nsx_security_policy_test.go index 5bef4affc..8ef8bcd7c 100644 --- a/test/e2e/nsx_security_policy_test.go +++ b/test/e2e/nsx_security_policy_test.go @@ -15,7 +15,6 @@ package e2e import ( - "fmt" "path/filepath" "testing" @@ -23,7 +22,7 @@ import ( ) const ( - SP = "securitypolicy" + SP = "securitypolicies.crd.nsx.vmware.com" ) // TestSecurityPolicyBasicTraffic verifies that the basic traffic of security policy. @@ -241,7 +240,6 @@ func TestSecurityPolicyNamedPortWithoutPod(t *testing.T) { nsClient := "client" nsWeb := "web" securityPolicyCRName := "named-port-policy-without-pod" - securityPolicyNSXDisplayName := fmt.Sprintf("sp-%s-%s", nsWeb, securityPolicyCRName) webA := "web" labelWeb := "tcp-deployment" ruleName0 := "all-ingress-isolation" @@ -266,7 +264,7 @@ func TestSecurityPolicyNamedPortWithoutPod(t *testing.T) { assertNil(t, err, "Error when waiting for Security Policy %s", securityPolicyCRName) // Check NSX resource existing - err = testData.waitForResourceExistOrNot(nsWeb, common.ResourceTypeSecurityPolicy, securityPolicyNSXDisplayName, true) + err = testData.waitForResourceExistOrNot(nsWeb, common.ResourceTypeSecurityPolicy, securityPolicyCRName, true) assertNil(t, err) err = testData.waitForResourceExistOrNot(nsWeb, common.ResourceTypeRule, ruleName0, true) assertNil(t, err) diff --git a/test/e2e/nsx_subnet_test.go b/test/e2e/nsx_subnet_test.go index 5b070346c..1421a14db 100644 --- a/test/e2e/nsx_subnet_test.go +++ b/test/e2e/nsx_subnet_test.go @@ -14,39 +14,39 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) const ( - SubnetSetCRType = "subnetsets" - SubnetPortCRType = "subnetport" + SubnetSetCRType = "subnetsets.crd.nsx.vmware.com" + SubnetPortCRType = "subnetports.crd.nsx.vmware.com" E2ENamespace = "subnet-e2e" E2ENamespaceShared = "subnet-e2e-shared" E2ENamespaceTarget = "target-ns" VPCNetworkConfigCRName = "default" // SubnetDeletionTimeout requires a bigger value than defaultTimeout, it's because that it takes some time for NSX to // recycle allocated IP addresses and NSX VPCSubnet won't be deleted until all IP addresses have been recycled. - SubnetDeletionTimeout = 300 * time.Second + SubnetDeletionTimeout = 600 * time.Second ) func verifySubnetSetCR(subnetSet string) bool { - vpcNetworkConfig, err := testData.crdClientset.NsxV1alpha1().VPCNetworkConfigurations().Get(context.TODO(), VPCNetworkConfigCRName, v1.GetOptions{}) + vpcNetworkConfig, err := testData.crdClientset.CrdV1alpha1().VPCNetworkConfigurations().Get(context.TODO(), VPCNetworkConfigCRName, + v1.GetOptions{}) if err != nil { log.Printf("Failed to get VPCNetworkConfiguration %s: %v", VPCNetworkConfigCRName, err) return false } - subnetSetCR, err := testData.crdClientset.NsxV1alpha1().SubnetSets(E2ENamespace).Get(context.TODO(), subnetSet, v1.GetOptions{}) + subnetSetCR, err := testData.crdClientset.CrdV1alpha1().SubnetSets(E2ENamespace).Get(context.TODO(), subnetSet, v1.GetOptions{}) if err != nil { log.Printf("Failed to get %s/%s: %s", E2ENamespace, subnetSet, err) return false } - if string(subnetSetCR.Spec.AccessMode) != vpcNetworkConfig.Spec.DefaultSubnetAccessMode { - log.Printf("AccessMode is %s, while it's expected to be %s", subnetSetCR.Spec.AccessMode, vpcNetworkConfig.Spec.DefaultSubnetAccessMode) - return false - } - if subnetSetCR.Spec.IPv4SubnetSize != vpcNetworkConfig.Spec.DefaultIPv4SubnetSize { - log.Printf("IPv4SubnetSize is %d, while it's expected to be %d", subnetSetCR.Spec.IPv4SubnetSize, vpcNetworkConfig.Spec.DefaultIPv4SubnetSize) + + if subnetSetCR.Spec.IPv4SubnetSize != vpcNetworkConfig.Spec.DefaultSubnetSize { + log.Printf("IPv4SubnetSize is %d, while it's expected to be %d", subnetSetCR.Spec.IPv4SubnetSize, vpcNetworkConfig.Spec.DefaultSubnetSize) return false } return true @@ -70,6 +70,32 @@ func TestSubnetSet(t *testing.T) { t.Run("case=SubnetCIDR", SubnetCIDR) } +func transSearchResponsetoSubnet(response model.SearchResponse) []model.VpcSubnet { + var resources []model.VpcSubnet + if response.Results == nil { + return resources + } + for _, result := range response.Results { + obj, err := common.NewConverter().ConvertToGolang(result, model.VpcSubnetBindingType()) + if err != nil { + log.Printf("Failed to convert to golang subnet: %v", err) + return resources + } + if subnet, ok := obj.(model.VpcSubnet); ok { + resources = append(resources, subnet) + } + } + return resources +} + +func fetchSubnet(t *testing.T, subnetSet *v1alpha1.SubnetSet) model.VpcSubnet { + tags := []string{common.TagScopeSubnetSetCRUID, string(subnetSet.UID)} + results, err := testData.queryResource(common.ResourceTypeSubnet, tags) + assertNil(t, err) + subnets := transSearchResponsetoSubnet(results) + assertTrue(t, len(subnets) > 0, "No NSX subnet found") + return subnets[0] +} func defaultSubnetSet(t *testing.T) { // 1. Check whether default-vm-subnetset and default-pod-subnetset are created. err := testData.waitForCRReadyOrDeleted(defaultTimeout, SubnetSetCRType, E2ENamespace, common.DefaultVMSubnetSet, Ready) @@ -84,20 +110,17 @@ func defaultSubnetSet(t *testing.T) { portPath, _ := filepath.Abs("./manifest/testSubnet/subnetport_1.yaml") err = applyYAML(portPath, E2ENamespace) assertNil(t, err) - err = testData.waitForCRReadyOrDeleted(defaultTimeout, SubnetPortCRType, E2ENamespace, "port-1", Ready) + err = testData.waitForCRReadyOrDeleted(defaultTimeout, SubnetPortCRType, E2ENamespace, "port-e2e-test-1", Ready) assertNil(t, err) defer deleteYAML(portPath, E2ENamespace) // 3. Check SubnetSet CR status should be updated with NSX subnet info. - subnetSet, err := testData.crdClientset.NsxV1alpha1().SubnetSets(E2ENamespace).Get(context.TODO(), common.DefaultPodSubnetSet, v1.GetOptions{}) + subnetSet, err := testData.crdClientset.CrdV1alpha1().SubnetSets(E2ENamespace).Get(context.TODO(), common.DefaultPodSubnetSet, v1.GetOptions{}) assertNil(t, err) assert.NotEmpty(t, subnetSet.Status.Subnets, "No Subnet info in SubnetSet") // 4. Check NSX subnet allocation. - subnetPath := subnetSet.Status.Subnets[0].NSXResourcePath - vpcInfo, err := common.ParseVPCResourcePath(subnetPath) - assertNil(t, err, "Failed to parse VPC resource path %s", subnetPath) - vpcSubnet, err := testData.nsxClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, vpcInfo.ID) - assertNil(t, err, "Failed to get VPC subnet %s", vpcInfo.ID) + networkAddress := subnetSet.Status.Subnets[0].NetworkAddresses + assertTrue(t, len(networkAddress) > 0, "No network address in SubnetSet") // 5. Check adding NSX subnet tags. ns, err := testData.clientset.CoreV1().Namespaces().Get(context.TODO(), E2ENamespace, v1.GetOptions{}) @@ -107,8 +130,8 @@ func defaultSubnetSet(t *testing.T) { ns, err = testData.clientset.CoreV1().Namespaces().Update(context.TODO(), ns, v1.UpdateOptions{}) time.Sleep(5 * time.Second) assertNil(t, err) - vpcSubnet, err = testData.nsxClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, vpcInfo.ID) - assertNil(t, err) + + vpcSubnet := fetchSubnet(t, subnetSet) found := false for _, tag := range vpcSubnet.Tags { if *tag.Scope == labelKey && *tag.Tag == labelValue { @@ -116,7 +139,7 @@ func defaultSubnetSet(t *testing.T) { break } } - assertTrue(t, found, "Failed to add tags for NSX subnet %s", vpcInfo.ID) + assertTrue(t, found, "Failed to add tags for NSX subnet %s", *(vpcSubnet.Id)) // 6. Check updating NSX subnet tags. labelValue = "update" @@ -124,8 +147,7 @@ func defaultSubnetSet(t *testing.T) { ns, err = testData.clientset.CoreV1().Namespaces().Update(context.TODO(), ns, v1.UpdateOptions{}) time.Sleep(5 * time.Second) assertNil(t, err) - vpcSubnet, err = testData.nsxClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, vpcInfo.ID) - assertNil(t, err) + vpcSubnet = fetchSubnet(t, subnetSet) found = false for _, tag := range vpcSubnet.Tags { if *tag.Scope == labelKey && *tag.Tag == labelValue { @@ -133,15 +155,14 @@ func defaultSubnetSet(t *testing.T) { break } } - assertTrue(t, found, "Failed to update tags for NSX subnet %s", vpcInfo.ID) + assertTrue(t, found, "Failed to update tags for NSX subnet %s", *(vpcSubnet.Id)) // 7. Check deleting NSX subnet tags. delete(ns.Labels, labelKey) _, err = testData.clientset.CoreV1().Namespaces().Update(context.TODO(), ns, v1.UpdateOptions{}) time.Sleep(5 * time.Second) assertNil(t, err) - vpcSubnet, err = testData.nsxClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, vpcInfo.ID) - assertNil(t, err) + vpcSubnet = fetchSubnet(t, subnetSet) found = false for _, tag := range vpcSubnet.Tags { if *tag.Scope == labelKey { @@ -149,7 +170,7 @@ func defaultSubnetSet(t *testing.T) { break } } - assertFalse(t, found, "Failed to delete tags for NSX subnet %s", vpcInfo.ID) + assertFalse(t, found, "Failed to delete tags for NSX subnet %s", *(vpcSubnet.Id)) } func UserSubnetSet(t *testing.T) { @@ -191,15 +212,22 @@ func UserSubnetSet(t *testing.T) { defer deleteYAML(portPath, E2ENamespace) // 3. Check SubnetSet CR status should be updated with NSX subnet info. - subnetSet, err := testData.crdClientset.NsxV1alpha1().SubnetSets(E2ENamespace).Get(context.TODO(), subnetSetName, v1.GetOptions{}) + subnetSet, err := testData.crdClientset.CrdV1alpha1().SubnetSets(E2ENamespace).Get(context.TODO(), subnetSetName, v1.GetOptions{}) assertNil(t, err) assert.NotEmpty(t, subnetSet.Status.Subnets, "No Subnet info in SubnetSet") - // 4. Check NSX subnet allocation. - subnetPath := subnetSet.Status.Subnets[0].NSXResourcePath - vpcInfo, err := common.ParseVPCResourcePath(subnetPath) - assertNil(t, err, "Failed to parse VPC resource path %s", subnetPath) - _, err = testData.nsxClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, vpcInfo.ID) - assertNil(t, err, "Failed to get VPC subnet %s", vpcInfo.ID) + + // 4. Check IP address is (not) allocated to SubnetPort. + port, err := testData.crdClientset.CrdV1alpha1().SubnetPorts(E2ENamespace).Get(context.TODO(), portName, v1.GetOptions{}) + assertNil(t, err) + if portName == "port-in-static-subnetset" { + assert.NotEmpty(t, port.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress, "No IP address in SubnetPort") + } else if portName == "port-in-dhcp-subnetset" { + assert.Empty(t, port.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress, "DHCP port shouldn't have IP Address") + } + + // 5. Check NSX subnet allocation. + networkaddress := subnetSet.Status.Subnets[0].NetworkAddresses + assertTrue(t, len(networkaddress) > 0, "No network address in SubnetSet") } } @@ -217,24 +245,24 @@ func sharedSubnetSet(t *testing.T) { portPath, _ := filepath.Abs("./manifest/testSubnet/subnetport_3.yaml") err = applyYAML(portPath, E2ENamespaceShared) assertNil(t, err) - err = testData.waitForCRReadyOrDeleted(defaultTimeout, SubnetPortCRType, E2ENamespaceShared, "port-3", Ready) + err = testData.waitForCRReadyOrDeleted(defaultTimeout, SubnetPortCRType, E2ENamespaceShared, "port-e2e-test-3", Ready) assertNil(t, err) defer deleteYAML(portPath, E2ENamespaceShared) // 3. Check SubnetSet CR status should be updated with NSX subnet info. - subnetSet, err := testData.crdClientset.NsxV1alpha1().SubnetSets(E2ENamespaceTarget).Get(context.TODO(), common.DefaultVMSubnetSet, v1.GetOptions{}) + subnetSet, err := testData.crdClientset.CrdV1alpha1().SubnetSets(E2ENamespaceTarget).Get(context.TODO(), common.DefaultVMSubnetSet, v1.GetOptions{}) assertNil(t, err) assert.NotEmpty(t, subnetSet.Status.Subnets, "No Subnet info in SubnetSet") // 4. Check IP address is allocated to SubnetPort. - port, err := testData.crdClientset.NsxV1alpha1().SubnetPorts(E2ENamespaceShared).Get(context.TODO(), "port-3", v1.GetOptions{}) + port, err := testData.crdClientset.CrdV1alpha1().SubnetPorts(E2ENamespaceShared).Get(context.TODO(), "port-e2e-test-3", v1.GetOptions{}) assertNil(t, err) assert.NotEmpty(t, port.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress, "No IP address in SubnetPort") // 5. Check Subnet CIDR contains SubnetPort IP. portIP := net.ParseIP(strings.Split(port.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress, "/")[0]) - _, subnetCIDR, err := net.ParseCIDR(subnetSet.Status.Subnets[0].IPAddresses[0]) + _, subnetCIDR, err := net.ParseCIDR(subnetSet.Status.Subnets[0].NetworkAddresses[0]) assertNil(t, err) assertTrue(t, subnetCIDR.Contains(portIP)) } @@ -251,21 +279,21 @@ func SubnetCIDR(t *testing.T) { }, }, } - _, err := testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Create(context.TODO(), subnet, v1.CreateOptions{}) + _, err := testData.crdClientset.CrdV1alpha1().Subnets(E2ENamespace).Create(context.TODO(), subnet, v1.CreateOptions{}) if err != nil && errors.IsAlreadyExists(err) { err = nil } assertNil(t, err) - err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets", E2ENamespace, subnet.Name, Ready) + err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets.crd.nsx.vmware.com", E2ENamespace, subnet.Name, Ready) assertNil(t, err) - allocatedSubnet, err := testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) + allocatedSubnet, err := testData.crdClientset.CrdV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) assertNil(t, err) - targetCIDR := allocatedSubnet.Status.IPAddresses[0] - err = testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Delete(context.TODO(), subnet.Name, v1.DeleteOptions{}) + targetCIDR := allocatedSubnet.Status.NetworkAddresses[0] + err = testData.crdClientset.CrdV1alpha1().Subnets(E2ENamespace).Delete(context.TODO(), subnet.Name, v1.DeleteOptions{}) assertNil(t, err) err = wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 100*time.Second, false, func(ctx context.Context) (bool, error) { - _, err := testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) + _, err := testData.crdClientset.CrdV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) if err != nil && errors.IsNotFound(err) { return true, nil } @@ -274,14 +302,14 @@ func SubnetCIDR(t *testing.T) { assertNil(t, err) subnet.Spec.IPAddresses = []string{targetCIDR} - _, err = testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Create(context.TODO(), subnet, v1.CreateOptions{}) + _, err = testData.crdClientset.CrdV1alpha1().Subnets(E2ENamespace).Create(context.TODO(), subnet, v1.CreateOptions{}) if err != nil && errors.IsAlreadyExists(err) { err = nil } assertNil(t, err) - err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets", E2ENamespace, subnet.Name, Ready) + err = testData.waitForCRReadyOrDeleted(defaultTimeout*2, "subnets.crd.nsx.vmware.com", E2ENamespace, subnet.Name, Ready) assertNil(t, err) - allocatedSubnet, err = testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) + allocatedSubnet, err = testData.crdClientset.CrdV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) assertNil(t, err) - assert.Equal(t, targetCIDR, allocatedSubnet.Status.IPAddresses[0]) + assert.Equal(t, targetCIDR, allocatedSubnet.Status.NetworkAddresses[0]) } diff --git a/test/e2e/nsx_vpc_test.go b/test/e2e/nsx_vpc_test.go deleted file mode 100644 index 08c3669d8..000000000 --- a/test/e2e/nsx_vpc_test.go +++ /dev/null @@ -1,149 +0,0 @@ -package e2e - -import ( - "log" - "path/filepath" - "strings" - "testing" -) - -const ( - VPCCRType = "vpcs" - VPCNSXType = "Vpc" - PrivateIPBlockNSXType = "IpAddressBlock" - - InfraVPCNamespace = "kube-system" - SharedInfraVPCNamespace = "kube-public" - - DefaultPrivateCIDR1 = "172.28.0.0" - DefaultPrivateCIDR2 = "172.38.0.0" - InfraPrivateCIDR1 = "172.27.0.0" - InfraPrivateCIDR2 = "172.37.0.0" - CustomizedPrivateCIDR1 = "172.29.0.0" - CustomizedPrivateCIDR2 = "172.39.0.0" -) - -var ( - verify_keys = []string{"defaultSNATIP", "lbSubnetCIDR", "lbSubnetPath", "nsxResourcePath"} -) - -func verifyVPCCRCreated(t *testing.T, ns string, expect int) (string, string) { - // there should be one vpc created - resources, err := testData.getCRResource(defaultTimeout, VPCCRType, ns) - // only one vpc should be created under ns using default network config - if len(resources) != expect { - log.Printf("VPC list %s size not the same as expected %d", resources, expect) - panic("VPC CR creation verify failed") - } - assertNil(t, err) - - var vpc_name, vpc_uid string = "", "" - // waiting for CR to be ready - for k, v := range resources { - vpc_name = k - vpc_uid = strings.TrimSpace(v) - } - - return vpc_name, vpc_uid -} - -func verifyPrivateIPBlockCreated(t *testing.T, ns, id string) { - err := testData.waitForResourceExistById(ns, PrivateIPBlockNSXType, id, true) - assertNil(t, err) -} - -func verifyVPCCRProperties(t *testing.T, ns, vpc_name string) { - for _, key := range verify_keys { - value, err := testData.getCRProperties(defaultTimeout, VPCCRType, vpc_name, ns, key) - assertNil(t, err) - if strings.TrimSpace(value) == "" { - log.Printf("failed to read key %s for VPC %s", key, vpc_name) - panic("failed to read attribute from VPC CR") - } - } -} - -// Test Customized VPC -func TestCustomizedVPC(t *testing.T) { - // Create customized networkconfig - ncPath, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig.yaml") - _ = applyYAML(ncPath, "") - nsPath, _ := filepath.Abs("./manifest/testVPC/customize_ns.yaml") - _ = applyYAML(nsPath, "") - - defer deleteYAML(nsPath, "") - defer deleteYAML(ncPath, "") - - ns := "customized-ns" - - vpc_name, vpc_uid := verifyVPCCRCreated(t, ns, 1) - - err := testData.waitForCRReadyOrDeleted(defaultTimeout, VPCCRType, ns, vpc_name, Ready) - assertNil(t, err, "Error when waiting for VPC %s", vpc_name) - - verifyVPCCRProperties(t, ns, vpc_name) - - // Check nsx-t resource existing, nsx vpc is using vpc cr uid as id - err = testData.waitForResourceExistById(ns, VPCNSXType, vpc_uid, true) - assertNil(t, err) - - //verify private ipblocks created for vpc - p_ipb_id1 := vpc_uid + "_" + CustomizedPrivateCIDR1 - p_ipb_id2 := vpc_uid + "_" + CustomizedPrivateCIDR2 - - verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) - verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) -} - -// Test Infra VPC -func TestInfraVPC(t *testing.T) { - // there should be one shared vpc created under namespace kube-system - vpc_name, vpc_uid := verifyVPCCRCreated(t, InfraVPCNamespace, 1) - - err := testData.waitForCRReadyOrDeleted(defaultTimeout, VPCCRType, InfraVPCNamespace, vpc_name, Ready) - assertNil(t, err, "Error when waiting for VPC %s", vpc_name) - - verifyVPCCRProperties(t, InfraVPCNamespace, vpc_name) - - // Check nsx-t resource existing, nsx vpc is using vpc cr uid as id - err = testData.waitForResourceExistById(InfraVPCNamespace, VPCNSXType, vpc_uid, true) - assertNil(t, err) - - //verify private ipblocks created for vpc - p_ipb_id1 := vpc_uid + "_" + InfraPrivateCIDR1 - p_ipb_id2 := vpc_uid + "_" + InfraPrivateCIDR2 - - verifyPrivateIPBlockCreated(t, InfraVPCNamespace, p_ipb_id1) - verifyPrivateIPBlockCreated(t, InfraVPCNamespace, p_ipb_id2) - - // there should be no VPC exist under namespace kube-public - _, _ = verifyVPCCRCreated(t, SharedInfraVPCNamespace, 0) -} - -// Test Default VPC -func TestDefaultVPC(t *testing.T) { - // If no annotation on namespace, then VPC will use default network config to create - // VPC under each ns - ns := "vpc-default-1" - setupTest(t, ns) - defer teardownTest(t, ns, defaultTimeout) - - // Check vpc cr existence - vpc_name, vpc_uid := verifyVPCCRCreated(t, ns, 1) - - err := testData.waitForCRReadyOrDeleted(defaultTimeout, VPCCRType, ns, vpc_name, Ready) - assertNil(t, err, "Error when waiting for VPC %s", vpc_name) - - verifyVPCCRProperties(t, ns, vpc_name) - - // Check nsx-t resource existing, nsx vpc is using vpc cr uid as id - err = testData.waitForResourceExistById(ns, VPCNSXType, vpc_uid, true) - assertNil(t, err) - - //verify private ipblocks created for vpc - p_ipb_id1 := vpc_uid + "_" + DefaultPrivateCIDR1 - p_ipb_id2 := vpc_uid + "_" + DefaultPrivateCIDR2 - - verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) - verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) -}