Skip to content

Commit 9bb743e

Browse files
committed
rfc: IGP resource, controller, and provider
Add a Custom Resource for Interior Gateway Protocol (IGP) spec. While we plan support for ISIS and OSPF, we consider only ISIS here. We also include a `cisco-nxos-gnmi` provider with an `isis` pkg to configure ISIS over gNMI using ygot objects from openconfig. This provider does not implement yet the `interface` resource. Both the resource and the provider implementation DO NOT support multiple IGP processes on the same device.
1 parent 7776fa9 commit 9bb743e

27 files changed

+1537
-113
lines changed

Tiltfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ k8s_resource(new_name='eth1-1', objects=['eth1-1:interface'], trigger_mode=TRIGG
3737
k8s_resource(new_name='eth1-2', objects=['eth1-2:interface'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)
3838
k8s_resource(new_name='eth1-10', objects=['eth1-10:interface'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)
3939

40+
k8s_yaml('./config/samples/v1alpha1_igp.yaml')
41+
k8s_resource(new_name='leaf1-underlay-isis', objects=['leaf1-underlay-isis:igp'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)
42+
4043
print('🚀 network-operator development environment')
4144
print('👉 Edit the code inside the api/, cmd/, or internal/ directories')
4245
print('👉 Tilt will automatically rebuild and redeploy when changes are detected')

api/v1alpha1/igp_types.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package v1alpha1
5+
6+
import (
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
)
9+
10+
// +kubebuilder:validation:Enum=ISIS
11+
type IGPType string
12+
13+
// IGProcessSpec defines the desired state of Interior Gateway Protocol (IGP) process on a device.
14+
type IGPSpec struct {
15+
// The name of the routing instance.
16+
//+kubebuilder:validation:Required
17+
Name string `json:"name"`
18+
//+kubebuilder:validation:Required
19+
ISIS ISISSpec `json:"isis,omitempty"`
20+
}
21+
22+
// +kubebuilder:validation:Enum=Level1;Level2;Level12
23+
type ISISLevel string
24+
25+
const (
26+
Level1 ISISLevel = "Level1"
27+
Level2 ISISLevel = "Level2"
28+
Level12 ISISLevel = "Level12"
29+
)
30+
31+
// +kubebuilder:validation:Enum=IPv4Unicast;IPv6Unicast
32+
type ISISAF string
33+
34+
const (
35+
IPv4Unicast ISISAF = "IPv4Unicast"
36+
IPv6Unicast ISISAF = "IPv6Unicast"
37+
)
38+
39+
type OverloadBit struct {
40+
// Duration of the OverloadBit in seconds.
41+
//+kubebuilder:validation:Required
42+
//+kubebuilder:validation:Minimum=576
43+
//+kubebuilder:validation:Maximum=86400
44+
OnStartup uint32 `json:"onStartup"`
45+
}
46+
47+
type ISISSpec struct {
48+
// The Network Entity Title (NET) for the ISIS instance.
49+
//+kubebuilder:validation:Required
50+
NET string `json:"net"`
51+
// The is-type of the process (the level)
52+
//+kubebuilder:validation:Required
53+
Level ISISLevel `json:"level"`
54+
// Overload bit configuration for this ISIS instance
55+
//+kubebuilder:validation:Optional
56+
OverloadBit *OverloadBit `json:"overloadBit"`
57+
//+kubebuilder:validation:Required
58+
//+kubebuilder:validation:MinItems=1
59+
//+kubebuilder:validation:MaxItems=2
60+
AddressFamilies []ISISAF `json:"addressFamilies,omitempty"`
61+
}
62+
63+
// IGPStatus defines the observed state of an IGP process.
64+
type IGPStatus struct {
65+
// The conditions are a list of status objects that describe the state of the Interface.
66+
//+listType=map
67+
//+listMapKey=type
68+
//+patchStrategy=merge
69+
//+patchMergeKey=type
70+
//+optional
71+
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
72+
}
73+
74+
// +kubebuilder:object:root=true
75+
// +kubebuilder:subresource:status
76+
// +kubebuilder:resource:path=igps
77+
// +kubebuilder:resource:singular=igp
78+
// +kubebuilder:resource:shortName=igp
79+
// +kubebuilder:printcolumn:name="Process name",type=string,JSONPath=`.spec.name`
80+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
81+
82+
// IGP is the Schema for the igp API.
83+
type IGP struct {
84+
metav1.TypeMeta `json:",inline"`
85+
metav1.ObjectMeta `json:"metadata,omitempty"`
86+
87+
// Specification of the desired state of the resource.
88+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
89+
Spec IGPSpec `json:"spec,omitempty"`
90+
91+
// Status of the resource. This is set and updated automatically.
92+
// Read-only.
93+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
94+
Status IGPStatus `json:"status,omitempty"`
95+
}
96+
97+
// +kubebuilder:object:root=true
98+
99+
// IGPList contains a list of IGP (processes).
100+
type IGPList struct {
101+
metav1.TypeMeta `json:",inline"`
102+
metav1.ListMeta `json:"metadata,omitempty"`
103+
Items []IGP `json:"items"`
104+
}
105+
106+
func init() {
107+
SchemeBuilder.Register(&IGP{}, &IGPList{})
108+
}

api/v1alpha1/zz_generated.deepcopy.go

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

cmd/main.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ func main() {
8080
flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
8181
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
8282
flag.BoolVar(&enableHTTP2, "enable-http2", false, "If set, HTTP/2 will be enabled for the metrics and webhook servers")
83-
flag.StringVar(&watchFilterValue, "watch-filter", "", fmt.Sprintf("Label value that the controller watches to reconcile api objects. Label key is always %q. If unspecified, the controller watches for all api objects.", v1alpha1.WatchLabel))
84-
flag.StringVar(&providerName, "provider", "openconfig", "The provider to use for the controller. If not specified, the default provider is used. Available providers: "+strings.Join(provider.Providers(), ", "))
83+
flag.StringVar(&watchFilterValue, "watch-filter", "", fmt.Sprintf("Label value that the controllers watch to reconcile api objects. Label key is always %q. If unspecified, the controller watches for all api objects.", v1alpha1.WatchLabel))
84+
flag.StringVar(&providerName, "provider", "openconfig", "The provider to use for the controllers. If not specified, the default provider is used. Available providers: "+strings.Join(provider.Providers(), ", "))
8585
opts := zap.Options{
8686
Development: true,
8787
TimeEncoder: zapcore.ISO8601TimeEncoder,
@@ -233,6 +233,17 @@ func main() {
233233
os.Exit(1)
234234
}
235235

236+
if err = (&controller.IGPReconciler{
237+
Client: mgr.GetClient(),
238+
Scheme: mgr.GetScheme(),
239+
Recorder: mgr.GetEventRecorderFor("igp-controller"),
240+
WatchFilterValue: watchFilterValue,
241+
Provider: prov,
242+
}).SetupWithManager(mgr); err != nil {
243+
setupLog.Error(err, "unable to create controller", "controller", "IGP")
244+
os.Exit(1)
245+
}
246+
236247
// +kubebuilder:scaffold:builder
237248

238249
if metricsCertWatcher != nil {

0 commit comments

Comments
 (0)