Skip to content

Commit c311a9c

Browse files
authored
feat: support reserved_internal_range in ComputeSubnetwork (#7719) (#11557)
Implement reserved_internal_range in ComputeSubnetwork.spec and ComputeSubnetwork.spec.secondaryIpRange - Add reserved_internal_range to ComputeSubnetworkSpec and SubnetworkSecondaryRange API definitions - Make ip_cidr_range optional when reserved_internal_range is configured - Update vendored TPG Beta schema, flatteners, and expanders for reserved_internal_range - Implement MockGCP support for CIDR range auto-allocation and patch operations - Add new E2E basic golden test fixture for reservedInternalRange Fixes #7719
2 parents a634d60 + af796c9 commit c311a9c

34 files changed

Lines changed: 2676 additions & 115 deletions

File tree

apis/compute/v1beta1/computesubnetwork_types.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package v1beta1
1616

1717
import (
1818
computerefs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/compute/refs"
19+
networkconnectivityrefs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/networkconnectivity/networkconnectivityrefs"
1920
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
)
@@ -35,7 +36,7 @@ type ComputeSubnetworkSpec struct {
3536
// Provide this property when you create the subnetwork. For example,
3637
// 10.0.0.0/8 or 192.168.0.0/16. Ranges must be unique and
3738
// non-overlapping within a network. Only IPv4 is supported.
38-
// +required
39+
// Field is optional when 'reservedInternalRangeRef' is defined, otherwise required.
3940
// +kcc:proto:field=google.cloud.compute.v1.Subnetwork.ip_cidr_range
4041
IPCIDRRange *string `json:"ipCidrRange,omitempty"`
4142

@@ -81,6 +82,10 @@ type ComputeSubnetworkSpec struct {
8182
// +required
8283
Region *string `json:"region"`
8384

85+
// Immutable. The reference to the reserved internal range.
86+
// +kcc:proto:field=google.cloud.compute.v1.Subnetwork.reserved_internal_range
87+
ReservedInternalRangeRef *networkconnectivityrefs.NetworkConnectivityInternalRangeRef `json:"reservedInternalRangeRef,omitempty"`
88+
8489
// Immutable. Optional. The name of the resource. Used for
8590
// creation and acquisition. When unset, the value of `metadata.name`
8691
// is used as the default.
@@ -211,13 +216,16 @@ type SubnetworkLogConfig struct {
211216

212217
// +kcc:proto=google.cloud.compute.v1.SubnetworkSecondaryRange
213218
type SubnetworkSecondaryRange struct {
214-
// The range of IP addresses belonging to this subnetwork secondary range. Provide this property when you create the subnetwork. Ranges must be unique and non-overlapping with all primary and secondary IP ranges within a network. Only IPv4 is supported. The range can be any range listed in the Valid ranges list.
215-
// +required
219+
// The range of IP addresses belonging to this subnetwork secondary range. Provide this property when you create the subnetwork. Ranges must be unique and non-overlapping with all primary and secondary IP ranges within a network. Only IPv4 is supported. Field is optional when 'reservedInternalRangeRef' is defined, otherwise required. The range can be any range listed in the Valid ranges list.
216220
// +kcc:proto:field=google.cloud.compute.v1.SubnetworkSecondaryRange.ip_cidr_range
217221
IPCIDRRange *string `json:"ipCidrRange,omitempty"`
218222

219223
// The name associated with this subnetwork secondary range, used when adding an alias IP range to a VM instance. The name must be 1-63 characters long, and comply with RFC1035. The name must be unique within the subnetwork.
220224
// +required
221225
// +kcc:proto:field=google.cloud.compute.v1.SubnetworkSecondaryRange.range_name
222226
RangeName *string `json:"rangeName,omitempty"`
227+
228+
// The reference to the reserved internal range.
229+
// +kcc:proto:field=google.cloud.compute.v1.SubnetworkSecondaryRange.reserved_internal_range
230+
ReservedInternalRangeRef *networkconnectivityrefs.NetworkConnectivityInternalRangeRef `json:"reservedInternalRangeRef,omitempty"`
223231
}

apis/compute/v1beta1/zz_generated.deepcopy.go

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// +k8s:deepcopy-gen=package
16+
package networkconnectivityrefs
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package networkconnectivityrefs
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common/identity"
21+
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/gcpurls"
22+
)
23+
24+
var (
25+
_ identity.IdentityV2 = &NetworkConnectivityInternalRangeIdentity{}
26+
)
27+
28+
var NetworkConnectivityInternalRangeIdentityFormat = gcpurls.Template[NetworkConnectivityInternalRangeIdentity]("networkconnectivity.googleapis.com", "projects/{project}/locations/{location}/internalRanges/{internalRange}")
29+
30+
type NetworkConnectivityInternalRangeIdentity struct {
31+
Project string
32+
Location string
33+
InternalRange string
34+
}
35+
36+
func (i *NetworkConnectivityInternalRangeIdentity) String() string {
37+
return NetworkConnectivityInternalRangeIdentityFormat.ToString(*i)
38+
}
39+
40+
func (i *NetworkConnectivityInternalRangeIdentity) FromExternal(ref string) error {
41+
parsed, match, err := NetworkConnectivityInternalRangeIdentityFormat.Parse(ref)
42+
if err != nil {
43+
return fmt.Errorf("format of NetworkConnectivityInternalRange external=%q was not known (use %s): %w", ref, NetworkConnectivityInternalRangeIdentityFormat.CanonicalForm(), err)
44+
}
45+
if !match {
46+
return fmt.Errorf("format of NetworkConnectivityInternalRange external=%q was not known (use %s)", ref, NetworkConnectivityInternalRangeIdentityFormat.CanonicalForm())
47+
}
48+
49+
*i = *parsed
50+
return nil
51+
}
52+
53+
func (i *NetworkConnectivityInternalRangeIdentity) Host() string {
54+
return NetworkConnectivityInternalRangeIdentityFormat.Host()
55+
}

apis/networkconnectivity/v1alpha1/networkconnectivityinternalrange_identity_test.go renamed to apis/networkconnectivity/networkconnectivityrefs/networkconnectivityinternalrange_identity_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,25 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package v1alpha1
15+
package networkconnectivityrefs_test
1616

1717
import (
1818
"testing"
19+
20+
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/networkconnectivity/networkconnectivityrefs"
1921
)
2022

21-
func TestInternalRangeIdentity_FromExternal(t *testing.T) {
23+
func TestNetworkConnectivityInternalRangeIdentity_FromExternal(t *testing.T) {
2224
tests := []struct {
2325
name string
2426
ref string
2527
wantErr bool
26-
want *InternalRangeIdentity
28+
want *networkconnectivityrefs.NetworkConnectivityInternalRangeIdentity
2729
}{
2830
{
2931
name: "valid reference",
3032
ref: "projects/my-project/locations/us-central1/internalRanges/my-internal-range",
31-
want: &InternalRangeIdentity{
33+
want: &networkconnectivityrefs.NetworkConnectivityInternalRangeIdentity{
3234
Project: "my-project",
3335
Location: "us-central1",
3436
InternalRange: "my-internal-range",
@@ -42,7 +44,7 @@ func TestInternalRangeIdentity_FromExternal(t *testing.T) {
4244
{
4345
name: "full url",
4446
ref: "https://networkconnectivity.googleapis.com/projects/my-project/locations/us-central1/internalRanges/my-internal-range",
45-
want: &InternalRangeIdentity{
47+
want: &networkconnectivityrefs.NetworkConnectivityInternalRangeIdentity{
4648
Project: "my-project",
4749
Location: "us-central1",
4850
InternalRange: "my-internal-range",
@@ -52,7 +54,7 @@ func TestInternalRangeIdentity_FromExternal(t *testing.T) {
5254

5355
for _, tt := range tests {
5456
t.Run(tt.name, func(t *testing.T) {
55-
i := &InternalRangeIdentity{}
57+
i := &networkconnectivityrefs.NetworkConnectivityInternalRangeIdentity{}
5658
err := i.FromExternal(tt.ref)
5759
if (err != nil) != tt.wantErr {
5860
t.Errorf("FromExternal() error = %v, wantErr %v", err, tt.wantErr)

apis/networkconnectivity/v1alpha1/networkconnectivityinternalrange_reference.go renamed to apis/networkconnectivity/networkconnectivityrefs/networkconnectivityinternalrange_reference.go

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,82 +12,100 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package v1alpha1
15+
package networkconnectivityrefs
1616

1717
import (
1818
"context"
19+
"fmt"
1920

2021
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common/identity"
22+
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/kccscheme"
2123
refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
2224
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2325
"k8s.io/apimachinery/pkg/runtime/schema"
2426
"k8s.io/apimachinery/pkg/types"
2527
"sigs.k8s.io/controller-runtime/pkg/client"
2628
)
2729

28-
var _ refs.Ref = &InternalRangeRef{}
30+
var NetworkConnectivityInternalRangeGVK = schema.GroupVersionKind{
31+
Group: "networkconnectivity.cnrm.cloud.google.com",
32+
Version: "v1alpha1",
33+
Kind: "NetworkConnectivityInternalRange",
34+
}
35+
36+
var (
37+
_ refs.Ref = &NetworkConnectivityInternalRangeRef{}
38+
_ refs.ExternalRef = &NetworkConnectivityInternalRangeRef{}
39+
)
2940

30-
// InternalRangeRef is a reference to a NetworkConnectivityInternalRange.
31-
type InternalRangeRef struct {
41+
type NetworkConnectivityInternalRangeRef struct {
3242
// A reference to an externally managed NetworkConnectivityInternalRange resource.
3343
// Should be in the format "projects/{{projectID}}/locations/{{location}}/internalRanges/{{internalrangeID}}".
3444
External string `json:"external,omitempty"`
3545

36-
// The name of a NetworkConnectivityInternalRange resource.
46+
// The name field of a NetworkConnectivityInternalRange resource.
3747
Name string `json:"name,omitempty"`
3848

39-
// The namespace of a NetworkConnectivityInternalRange resource.
49+
// The namespace field of a NetworkConnectivityInternalRange resource.
4050
Namespace string `json:"namespace,omitempty"`
4151
}
4252

4353
func init() {
44-
refs.Register(&InternalRangeRef{}, &NetworkConnectivityInternalRange{})
54+
kccscheme.RegisterRef(&NetworkConnectivityInternalRangeRef{}, NetworkConnectivityInternalRangeGVK)
4555
}
4656

47-
func (r *InternalRangeRef) GetGVK() schema.GroupVersionKind {
57+
func (r *NetworkConnectivityInternalRangeRef) GetGVK() schema.GroupVersionKind {
4858
return NetworkConnectivityInternalRangeGVK
4959
}
5060

51-
func (r *InternalRangeRef) GetNamespacedName() types.NamespacedName {
61+
func (r *NetworkConnectivityInternalRangeRef) GetNamespacedName() types.NamespacedName {
5262
return types.NamespacedName{
5363
Name: r.Name,
5464
Namespace: r.Namespace,
5565
}
5666
}
5767

58-
func (r *InternalRangeRef) GetExternal() string {
68+
func (r *NetworkConnectivityInternalRangeRef) GetExternal() string {
5969
return r.External
6070
}
6171

62-
func (r *InternalRangeRef) SetExternal(ref string) {
72+
func (r *NetworkConnectivityInternalRangeRef) SetExternal(ref string) {
6373
r.External = ref
6474
r.Name = ""
6575
r.Namespace = ""
6676
}
6777

68-
func (r *InternalRangeRef) ValidateExternal(ref string) error {
69-
id := &InternalRangeIdentity{}
78+
func (r *NetworkConnectivityInternalRangeRef) ValidateExternal(ref string) error {
79+
id := &NetworkConnectivityInternalRangeIdentity{}
7080
if err := id.FromExternal(ref); err != nil {
7181
return err
7282
}
7383
return nil
7484
}
7585

76-
func (r *InternalRangeRef) ParseExternalToIdentity() (identity.Identity, error) {
77-
id := &InternalRangeIdentity{}
86+
func (r *NetworkConnectivityInternalRangeRef) ParseExternalToIdentity() (identity.Identity, error) {
87+
id := &NetworkConnectivityInternalRangeIdentity{}
7888
if err := id.FromExternal(r.External); err != nil {
7989
return nil, err
8090
}
8191
return id, nil
8292
}
8393

84-
func (r *InternalRangeRef) Normalize(ctx context.Context, reader client.Reader, defaultNamespace string) error {
94+
func (r *NetworkConnectivityInternalRangeRef) Normalize(ctx context.Context, reader client.Reader, defaultNamespace string) error {
8595
fallback := func(u *unstructured.Unstructured) string {
86-
identity, err := getIdentityFromInternalRangeSpec(ctx, reader, u)
96+
resourceID, err := refs.GetResourceID(u)
97+
if err != nil {
98+
return ""
99+
}
100+
location, _, _ := unstructured.NestedString(u.Object, "spec", "location")
101+
if location == "" {
102+
return ""
103+
}
104+
projectID, err := refs.ResolveProjectID(ctx, reader, u)
87105
if err != nil {
88106
return ""
89107
}
90-
return identity.String()
108+
return fmt.Sprintf("projects/%s/locations/%s/internalRanges/%s", projectID, location, resourceID)
91109
}
92110
return refs.NormalizeWithFallback(ctx, reader, r, defaultNamespace, fallback)
93111
}

apis/networkconnectivity/v1alpha1/networkconnectivityinternalrange_reference_test.go renamed to apis/networkconnectivity/networkconnectivityrefs/networkconnectivityinternalrange_reference_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package v1alpha1_test
15+
package networkconnectivityrefs_test
1616

1717
import (
1818
"testing"
1919

20-
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/networkconnectivity/v1alpha1"
20+
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/networkconnectivity/networkconnectivityrefs"
2121
)
2222

23-
func TestInternalRangeRef_ValidateExternal(t *testing.T) {
23+
func TestNetworkConnectivityInternalRangeRef_ValidateExternal(t *testing.T) {
2424
tests := []struct {
2525
name string
2626
ref string
@@ -55,9 +55,9 @@ func TestInternalRangeRef_ValidateExternal(t *testing.T) {
5555

5656
for _, tt := range tests {
5757
t.Run(tt.name, func(t *testing.T) {
58-
r := &v1alpha1.InternalRangeRef{}
58+
r := &networkconnectivityrefs.NetworkConnectivityInternalRangeRef{}
5959
if err := r.ValidateExternal(tt.ref); (err != nil) != tt.wantErr {
60-
t.Errorf("InternalRangeRef.ValidateExternal() error = %v, wantErr %v", err, tt.wantErr)
60+
t.Errorf("NetworkConnectivityInternalRangeRef.ValidateExternal() error = %v, wantErr %v", err, tt.wantErr)
6161
}
6262
})
6363
}

apis/networkconnectivity/networkconnectivityrefs/zz_generated.deepcopy.go

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)