Skip to content

Commit 4df7f32

Browse files
brueleaalexandernorthhenrybear327
authored
Support reservation of IpRanges (#130)
* add IpRange and IpRangeClaim apis * implement controllers * refactor controller * add unit tests * use availabe ips in range to create list for status * refactor iprange recondile funcitons * fix error handling * fix linting * set minimum size of irc to 2 * Apply suggestions from code review Co-authored-by: Alexander North <alexandernorth@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chun-Hung Tseng <henrybear327@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chun-Hung Tseng <henrybear327@users.noreply.github.com> * improvements based on review * improvements for review * rename generateManagedCustomFieldsAnnotation funciton * limit size of iprangeclaim CR to 50 * improve description of iprangeclaim.spec.size field --------- Co-authored-by: Alexander North <alexandernorth@users.noreply.github.com> Co-authored-by: Chun-Hung Tseng <henrybear327@users.noreply.github.com>
1 parent a0b6689 commit 4df7f32

38 files changed

+3161
-73
lines changed

PROJECT

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,20 @@ resources:
4040
kind: PrefixClaim
4141
path: github.com/netbox-community/netbox-operator/api/v1
4242
version: v1
43+
- api:
44+
crdVersion: v1
45+
namespaced: true
46+
controller: true
47+
domain: netbox.dev
48+
kind: IpRangeClaim
49+
path: github.com/netbox-community/netbox-operator/api/v1
50+
version: v1
51+
- api:
52+
crdVersion: v1
53+
namespaced: true
54+
controller: true
55+
domain: netbox.dev
56+
kind: IpRange
57+
path: github.com/netbox-community/netbox-operator/api/v1
58+
version: v1
4359
version: "3"

api/v1/iprange_types.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
Copyright 2024 Swisscom (Schweiz) AG.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
)
22+
23+
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
24+
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
25+
26+
// IpRangeSpec defines the desired state of IpRange
27+
type IpRangeSpec struct {
28+
// the startAddress is the first ip address included in the ip range
29+
//+kubebuilder:validation:Format=cidr
30+
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Field 'startAddress' is immutable"
31+
//+kubebuilder:validation:Required
32+
StartAddress string `json:"startAddress"`
33+
34+
// the endAddress is the last ip address included in the ip range
35+
//+kubebuilder:validation:Format=cidr
36+
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Field 'endAddress' is immutable"
37+
//+kubebuilder:validation:Required
38+
EndAddress string `json:"endAddress"`
39+
40+
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Field 'tenant' is immutable"
41+
Tenant string `json:"tenant,omitempty"`
42+
43+
CustomFields map[string]string `json:"customFields,omitempty"`
44+
45+
Comments string `json:"comments,omitempty"`
46+
47+
Description string `json:"description,omitempty"`
48+
49+
PreserveInNetbox bool `json:"preserveInNetbox,omitempty"`
50+
}
51+
52+
// IpRangeStatus defines the observed state of IpRange
53+
type IpRangeStatus struct {
54+
IpRangeId int64 `json:"id,omitempty"`
55+
56+
IpRangeUrl string `json:"url,omitempty"`
57+
58+
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
59+
}
60+
61+
//+kubebuilder:object:root=true
62+
//+kubebuilder:subresource:status
63+
//+kubebuilder:storageversion
64+
//+kubebuilder:printcolumn:name="StartAddress",type=string,JSONPath=`.spec.startAddress`
65+
//+kubebuilder:printcolumn:name="EndAddress",type=string,JSONPath=`.spec.endAddress`
66+
//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
67+
//+kubebuilder:printcolumn:name="ID",type=string,JSONPath=`.status.id`
68+
//+kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.status.url`
69+
//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
70+
// +kubebuilder:resource:shortName=ipr
71+
72+
// IpRange is the Schema for the ipranges API
73+
type IpRange struct {
74+
metav1.TypeMeta `json:",inline"`
75+
metav1.ObjectMeta `json:"metadata,omitempty"`
76+
77+
Spec IpRangeSpec `json:"spec,omitempty"`
78+
Status IpRangeStatus `json:"status,omitempty"`
79+
}
80+
81+
//+kubebuilder:object:root=true
82+
83+
// IpRangeList contains a list of IpRange
84+
type IpRangeList struct {
85+
metav1.TypeMeta `json:",inline"`
86+
metav1.ListMeta `json:"metadata,omitempty"`
87+
Items []IpRange `json:"items"`
88+
}
89+
90+
func init() {
91+
SchemeBuilder.Register(&IpRange{}, &IpRangeList{})
92+
}
93+
94+
var ConditionIpRangeReadyTrue = metav1.Condition{
95+
Type: "Ready",
96+
Status: "True",
97+
Reason: "IPRangeReservedInNetbox",
98+
Message: "IP Range was reserved/updated in NetBox",
99+
}
100+
101+
var ConditionIpRangeReadyFalse = metav1.Condition{
102+
Type: "Ready",
103+
Status: "False",
104+
Reason: "FailedToReserveIPRangeInNetbox",
105+
Message: "Failed to reserve IP Range in NetBox",
106+
}
107+
108+
var ConditionIpRangeReadyFalseDeletionFailed = metav1.Condition{
109+
Type: "Ready",
110+
Status: "False",
111+
Reason: "FailedToDeleteIPRangeInNetbox",
112+
Message: "Failed to delete IP Range in NetBox",
113+
}

api/v1/iprangeclaim_types.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
Copyright 2024 Swisscom (Schweiz) AG.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
)
22+
23+
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
24+
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
25+
26+
// IpRangeClaimSpec defines the desired state of IpRangeClaim
27+
type IpRangeClaimSpec struct {
28+
//+kubebuilder:validation:Required
29+
//+kubebuilder:validation:Format=cidr
30+
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Field 'parentPrefix' is immutable"
31+
ParentPrefix string `json:"parentPrefix"`
32+
33+
// Size is the amount of consecutive IP Addresses you wish to reserve. Currently only sizes up to 50 are supported due to pagination of the NetBox API. In practice, this might be even lower depending on the fragmentation of the parent prefix.
34+
//+kubebuilder:validation:Required
35+
//+kubebuilder:validation:Minimum=2
36+
//+kubebuilder:validation:Maximum=50
37+
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Field 'size' is immutable"
38+
Size int `json:"size,omitempty"`
39+
40+
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Field 'tenant' is immutable"
41+
Tenant string `json:"tenant,omitempty"`
42+
43+
CustomFields map[string]string `json:"customFields,omitempty"`
44+
45+
Comments string `json:"comments,omitempty"`
46+
47+
Description string `json:"description,omitempty"`
48+
49+
PreserveInNetbox bool `json:"preserveInNetbox,omitempty"`
50+
}
51+
52+
// IpRangeClaimStatus defines the observed state of IpRangeClaim
53+
type IpRangeClaimStatus struct {
54+
IpRange string `json:"ipRange,omitempty"`
55+
56+
IpRangeDotDecimal string `json:"ipRangeDotDecimal,omitempty"`
57+
58+
IpAddresses []string `json:"ipAddresses,omitempty"`
59+
60+
IpAddressesDotDecimal []string `json:"ipAddressesDotDecimal,omitempty"`
61+
62+
StartAddress string `json:"startAddress,omitempty"`
63+
64+
StartAddressDotDecimal string `json:"startAddressDotDecimal,omitempty"`
65+
66+
EndAddress string `json:"endAddress,omitempty"`
67+
68+
EndAddressDotDecimal string `json:"endAddressDotDecimal,omitempty"`
69+
70+
IpRangeName string `json:"ipAddressName,omitempty"`
71+
72+
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
73+
}
74+
75+
//+kubebuilder:object:root=true
76+
//+kubebuilder:subresource:status
77+
//+kubebuilder:storageversion
78+
//+kubebuilder:printcolumn:name="IpRange",type=string,JSONPath=`.status.ipRange`
79+
//+kubebuilder:printcolumn:name="IpRangeAssigned",type=string,JSONPath=`.status.conditions[?(@.type=="IPRangeAssigned")].status`
80+
//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
81+
//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
82+
// +kubebuilder:resource:shortName=iprc
83+
84+
// IpRangeClaim is the Schema for the iprangeclaims API
85+
type IpRangeClaim struct {
86+
metav1.TypeMeta `json:",inline"`
87+
metav1.ObjectMeta `json:"metadata,omitempty"`
88+
89+
Spec IpRangeClaimSpec `json:"spec,omitempty"`
90+
Status IpRangeClaimStatus `json:"status,omitempty"`
91+
}
92+
93+
//+kubebuilder:object:root=true
94+
95+
// IpRangeClaimList contains a list of IpRangeClaim
96+
type IpRangeClaimList struct {
97+
metav1.TypeMeta `json:",inline"`
98+
metav1.ListMeta `json:"metadata,omitempty"`
99+
Items []IpRangeClaim `json:"items"`
100+
}
101+
102+
func init() {
103+
SchemeBuilder.Register(&IpRangeClaim{}, &IpRangeClaimList{})
104+
}
105+
106+
var ConditionIpRangeClaimReadyTrue = metav1.Condition{
107+
Type: "Ready",
108+
Status: "True",
109+
Reason: "IPRangeResourceReady",
110+
Message: "IP Range Resource is ready",
111+
}
112+
113+
var ConditionIpRangeClaimReadyFalse = metav1.Condition{
114+
Type: "Ready",
115+
Status: "False",
116+
Reason: "IPRangeResourceNotReady",
117+
Message: "IP Range Resource is not ready",
118+
}
119+
120+
var ConditionIpRangeClaimReadyFalseStatusGen = metav1.Condition{
121+
Type: "Ready",
122+
Status: "False",
123+
Reason: "IPRangeClaimStatusGenerationFailed",
124+
Message: "Failed to generate IP Range Status",
125+
}
126+
127+
var ConditionIpRangeAssignedTrue = metav1.Condition{
128+
Type: "IPRangeAssigned",
129+
Status: "True",
130+
Reason: "IPRangeCRCreated",
131+
Message: "New IP Range fetched from NetBox and IpRange CR was created",
132+
}
133+
134+
var ConditionIpRangeAssignedFalse = metav1.Condition{
135+
Type: "IPRangeAssigned",
136+
Status: "False",
137+
Reason: "IPRangeCRNotCreated",
138+
Message: "Failed to fetch new IP Range from NetBox",
139+
}
140+
141+
var ConditionIpRangeAssignedFalseSizeMissmatch = metav1.Condition{
142+
Type: "IPRangeAssigned",
143+
Status: "False",
144+
Reason: "IPRangeCRNotCreated",
145+
Message: "Assigned/Restored IP range has less available IP addresses than requested",
146+
}

0 commit comments

Comments
 (0)