Skip to content

Commit 4d93cd4

Browse files
authored
Ingress will only have an IP address when type is LoadBalancer (#226)
1 parent 37a2167 commit 4d93cd4

File tree

2 files changed

+181
-27
lines changed

2 files changed

+181
-27
lines changed

pkg/appstate/ingress.go

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/replicatedhq/replicated-sdk/pkg/appstate/types"
88
"github.com/replicatedhq/replicated-sdk/pkg/k8sutil"
99
"github.com/replicatedhq/replicated-sdk/pkg/logger"
10+
v1 "k8s.io/api/core/v1"
1011
networkingv1 "k8s.io/api/networking/v1"
1112
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1213
"k8s.io/apimachinery/pkg/runtime"
@@ -118,6 +119,7 @@ func makeIngressResourceState(r *networkingv1.Ingress, state types.State) types.
118119
}
119120

120121
func CalculateIngressState(clientset kubernetes.Interface, r *networkingv1.Ingress) types.State {
122+
ctx := context.TODO()
121123
ns := r.Namespace
122124
backend := r.Spec.DefaultBackend
123125

@@ -139,30 +141,43 @@ func CalculateIngressState(clientset kubernetes.Interface, r *networkingv1.Ingre
139141
ns = metav1.NamespaceSystem
140142
}
141143

142-
var states []types.State
144+
services := []*v1.Service{} // includes nils which are mapped to unavailable
143145
if backend != nil {
144-
states = append(states, ingressGetStateFromBackend(clientset, ns, *backend))
146+
service, _ := clientset.CoreV1().Services(ns).Get(ctx, backend.Service.Name, metav1.GetOptions{})
147+
services = append(services, service)
145148
}
146149

147150
for _, rules := range r.Spec.Rules {
148151
for _, path := range rules.HTTP.Paths {
149-
states = append(states, ingressGetStateFromBackend(clientset, r.Namespace, path.Backend))
152+
service, _ := clientset.CoreV1().Services(r.Namespace).Get(ctx, path.Backend.Service.Name, metav1.GetOptions{})
153+
services = append(services, service)
150154
}
151155
}
152-
// https://github.com/kubernetes/kubernetes/blob/badcd4af3f592376ce891b7c1b7a43ed6a18a348/pkg/printers/internalversion/printers.go#L1067
153-
states = append(states, ingressGetStateFromExternalIP(r))
154-
return types.MinState(states...)
155-
}
156156

157-
func ingressGetStateFromBackend(clientset kubernetes.Interface, namespace string, backend networkingv1.IngressBackend) (minState types.State) {
158-
if backend.Service == nil {
159-
return types.StateUnavailable
157+
hasLoadBalancer := false
158+
for _, service := range services {
159+
if service != nil && service.Spec.Type == v1.ServiceTypeLoadBalancer {
160+
hasLoadBalancer = true
161+
break
162+
}
160163
}
161-
service, _ := clientset.CoreV1().Services(namespace).Get(context.TODO(), backend.Service.Name, metav1.GetOptions{})
162-
if service == nil {
163-
return types.StateUnavailable
164+
165+
var states []types.State
166+
for _, service := range services {
167+
if service == nil {
168+
states = append(states, types.StateUnavailable)
169+
} else {
170+
states = append(states, serviceGetStateFromEndpoints(clientset, service))
171+
}
172+
}
173+
174+
// An ingress will have an IP associated with it if it's type is LoadBalancer.
175+
if hasLoadBalancer {
176+
// https://github.com/kubernetes/kubernetes/blob/badcd4af3f592376ce891b7c1b7a43ed6a18a348/pkg/printers/internalversion/printers.go#L1067
177+
states = append(states, ingressGetStateFromExternalIP(r))
164178
}
165-
return serviceGetStateFromEndpoints(clientset, service)
179+
180+
return types.MinState(states...)
166181
}
167182

168183
func ingressGetStateFromExternalIP(ing *networkingv1.Ingress) types.State {

pkg/appstate/ingress_test.go

Lines changed: 152 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
func mockClientsetK8sVersion(expectedMajor string, expectedMinor string) kubernetes.Interface {
1818
clientset := fake.NewSimpleClientset(
19-
// add a service
19+
// Defaul backend service and endpoint
2020
&v1.Service{
2121
ObjectMeta: metav1.ObjectMeta{
2222
Name: "default-http-backend",
@@ -52,6 +52,82 @@ func mockClientsetK8sVersion(expectedMajor string, expectedMinor string) kuberne
5252
},
5353
},
5454
},
55+
56+
// LoadBalancer service and endpoint
57+
&v1.Service{
58+
ObjectMeta: metav1.ObjectMeta{
59+
Name: "app-lb",
60+
Namespace: "",
61+
},
62+
Spec: v1.ServiceSpec{
63+
Type: v1.ServiceTypeLoadBalancer,
64+
Ports: []v1.ServicePort{
65+
{
66+
Name: "http",
67+
Port: 8080,
68+
},
69+
},
70+
},
71+
},
72+
&v1.Endpoints{
73+
ObjectMeta: metav1.ObjectMeta{
74+
Name: "app-lb",
75+
Namespace: "",
76+
},
77+
Subsets: []v1.EndpointSubset{
78+
{
79+
Ports: []v1.EndpointPort{
80+
{
81+
Name: "http",
82+
Port: 8080,
83+
},
84+
},
85+
Addresses: []v1.EndpointAddress{
86+
{
87+
IP: "172.0.0.2",
88+
},
89+
},
90+
},
91+
},
92+
},
93+
94+
// NodePort service and endpoint
95+
&v1.Service{
96+
ObjectMeta: metav1.ObjectMeta{
97+
Name: "app-nodeport",
98+
Namespace: "",
99+
},
100+
Spec: v1.ServiceSpec{
101+
Type: v1.ServiceTypeNodePort,
102+
Ports: []v1.ServicePort{
103+
{
104+
Name: "http",
105+
Port: 8080,
106+
},
107+
},
108+
},
109+
},
110+
&v1.Endpoints{
111+
ObjectMeta: metav1.ObjectMeta{
112+
Name: "app-nodeport",
113+
Namespace: "",
114+
},
115+
Subsets: []v1.EndpointSubset{
116+
{
117+
Ports: []v1.EndpointPort{
118+
{
119+
Name: "http",
120+
Port: 8080,
121+
},
122+
},
123+
Addresses: []v1.EndpointAddress{
124+
{
125+
IP: "172.0.0.2",
126+
},
127+
},
128+
},
129+
},
130+
},
55131
)
56132
clientset.Discovery().(*discoveryfake.FakeDiscovery).FakedServerVersion = &version.Info{
57133
Major: expectedMajor,
@@ -88,22 +164,30 @@ func TestCalculateIngressState(t *testing.T) {
88164
},
89165
},
90166
want: types.StateReady,
91-
},
92-
{
93-
name: "expect unavailable state when ingress with k8s version > 1.22 and no default backend",
94-
args: args{
95-
clientset: mockClientsetK8sVersion("1", "23"),
96-
r: &networkingv1.Ingress{
97-
Spec: networkingv1.IngressSpec{},
98-
},
99-
},
100-
want: types.StateUnavailable,
101167
}, {
102-
name: "expect ready state when ingress with k8s version > 1.22 and no default backend and with load balancer status",
168+
name: "expect ready state when there is a load balancer and an IP address",
103169
args: args{
104170
clientset: mockClientsetK8sVersion("1", "23"),
105171
r: &networkingv1.Ingress{
106-
Spec: networkingv1.IngressSpec{},
172+
Spec: networkingv1.IngressSpec{
173+
Rules: []networkingv1.IngressRule{
174+
{
175+
IngressRuleValue: networkingv1.IngressRuleValue{
176+
HTTP: &networkingv1.HTTPIngressRuleValue{
177+
Paths: []networkingv1.HTTPIngressPath{
178+
{
179+
Backend: networkingv1.IngressBackend{
180+
Service: &networkingv1.IngressServiceBackend{
181+
Name: "app-lb",
182+
},
183+
},
184+
},
185+
},
186+
},
187+
},
188+
},
189+
},
190+
},
107191
Status: networkingv1.IngressStatus{
108192
LoadBalancer: networkingv1.IngressLoadBalancerStatus{
109193
Ingress: []networkingv1.IngressLoadBalancerIngress{
@@ -116,6 +200,61 @@ func TestCalculateIngressState(t *testing.T) {
116200
},
117201
},
118202
want: types.StateReady,
203+
}, {
204+
name: "expect ready state when there is no LoadBalancer and no address is assigned",
205+
args: args{
206+
clientset: mockClientsetK8sVersion("1", "23"),
207+
r: &networkingv1.Ingress{
208+
Spec: networkingv1.IngressSpec{
209+
Rules: []networkingv1.IngressRule{
210+
{
211+
IngressRuleValue: networkingv1.IngressRuleValue{
212+
HTTP: &networkingv1.HTTPIngressRuleValue{
213+
Paths: []networkingv1.HTTPIngressPath{
214+
{
215+
Backend: networkingv1.IngressBackend{
216+
Service: &networkingv1.IngressServiceBackend{
217+
Name: "app-nodeport",
218+
},
219+
},
220+
},
221+
},
222+
},
223+
},
224+
},
225+
},
226+
},
227+
Status: networkingv1.IngressStatus{},
228+
},
229+
},
230+
want: types.StateReady,
231+
}, {
232+
name: "expect unavailable state when there is a LoadBalancer but no address is assigned",
233+
args: args{
234+
clientset: mockClientsetK8sVersion("1", "23"),
235+
r: &networkingv1.Ingress{
236+
Spec: networkingv1.IngressSpec{
237+
Rules: []networkingv1.IngressRule{
238+
{
239+
IngressRuleValue: networkingv1.IngressRuleValue{
240+
HTTP: &networkingv1.HTTPIngressRuleValue{
241+
Paths: []networkingv1.HTTPIngressPath{
242+
{
243+
Backend: networkingv1.IngressBackend{
244+
Service: &networkingv1.IngressServiceBackend{
245+
Name: "app-lb",
246+
},
247+
},
248+
},
249+
},
250+
},
251+
},
252+
},
253+
},
254+
},
255+
},
256+
},
257+
want: types.StateUnavailable,
119258
},
120259
}
121260
for _, tt := range tests {

0 commit comments

Comments
 (0)