Skip to content

Commit 219c11f

Browse files
committed
fix: update redfish url validation
update validation for redfish url to give better error message when port number is not provided changed from using regex to using url.Parse to avoid any unforseen cases and support ipv6 added unit tests to cover changes Signed-off-by: ehila <[email protected]>
1 parent f93a306 commit 219c11f

File tree

2 files changed

+109
-10
lines changed

2 files changed

+109
-10
lines changed

pkg/tnf/pkg/pcs/fencing.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package pcs
33
import (
44
"context"
55
"fmt"
6-
"regexp"
6+
"net/url"
77
"strings"
88

99
corev1 "k8s.io/api/core/v1"
@@ -15,10 +15,6 @@ import (
1515
"github.com/openshift/cluster-etcd-operator/pkg/tnf/pkg/tools"
1616
)
1717

18-
var (
19-
addressRegEx = regexp.MustCompile(`.*//(.*):(.*)(/redfish.*)`)
20-
)
21-
2218
const (
2319
// defaultPcmkDelayBase is the delay applied to the first fence device to prevent simultaneous fencing
2420
defaultPcmkDelayBase = "10s"
@@ -130,12 +126,28 @@ func getFencingConfig(nodeName string, secret *corev1.Secret) (*fencingConfig, e
130126

131127
// we need to parse ip, port and systems uri from the address like this:
132128
// redfish+https://192.168.111.1:8000/redfish/v1/Systems/af2167e4-c13b-4941-b606-f912e9a86f4b
133-
matches := addressRegEx.FindStringSubmatch(address)
134-
if len(matches) != 4 {
129+
parsedUrl, err := url.Parse(address)
130+
if err != nil {
135131
klog.Errorf("Failed to parse redfish address %s", address)
136132
return nil, fmt.Errorf("failed to parse redfish address %s", address)
137133
}
138134

135+
redfishHostname := parsedUrl.Hostname()
136+
redfishPath := parsedUrl.Path
137+
redfishPort := parsedUrl.Port()
138+
// Try to infer standard schema ports for https/http, otherwise notify user port is needed.
139+
if redfishPort == "" {
140+
switch {
141+
case strings.Contains(parsedUrl.Scheme, "https"):
142+
redfishPort = "443"
143+
case strings.Contains(parsedUrl.Scheme, "http"):
144+
redfishPort = "80"
145+
default:
146+
klog.Errorf("Failed to parse redfish address, no port number found %s", address)
147+
return nil, fmt.Errorf("failed to parse redfish address, no port number found %s", address)
148+
}
149+
}
150+
139151
username := string(secret.Data["username"])
140152
if username == "" {
141153
klog.Errorf("Secret %s does not contain username", secret.Name)
@@ -159,9 +171,9 @@ func getFencingConfig(nodeName string, secret *corev1.Secret) (*fencingConfig, e
159171
FencingID: fmt.Sprintf("%s_%s", nodeName, "redfish"),
160172
FencingDeviceType: "fence_redfish",
161173
FencingDeviceOptions: map[fencingOption]string{
162-
Ip: matches[1],
163-
IpPort: matches[2],
164-
SystemsUri: matches[3],
174+
Ip: redfishHostname,
175+
IpPort: redfishPort,
176+
SystemsUri: redfishPath,
165177
Username: username,
166178
Password: password,
167179
},

pkg/tnf/pkg/pcs/fencing_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,81 @@ func TestGetFencingConfig(t *testing.T) {
6565
},
6666
},
6767
},
68+
{
69+
name: "valid redfish config without port number on https",
70+
nodeName: "node1",
71+
secret: &corev1.Secret{
72+
Data: map[string][]byte{
73+
"address": []byte("redfish+https://192.168.111.1/redfish/v1/Systems/abc"),
74+
"username": []byte("admin"),
75+
"password": []byte("pass123"),
76+
"certificateVerification": []byte("Enabled"),
77+
},
78+
},
79+
wantErr: false,
80+
expectedCfg: &fencingConfig{
81+
NodeName: "node1",
82+
FencingID: "node1_redfish",
83+
FencingDeviceType: "fence_redfish",
84+
FencingDeviceOptions: map[fencingOption]string{
85+
Ip: "192.168.111.1",
86+
IpPort: "443",
87+
SystemsUri: "/redfish/v1/Systems/abc",
88+
Username: "admin",
89+
Password: "pass123",
90+
},
91+
},
92+
},
93+
{
94+
name: "valid redfish config without port number on http",
95+
nodeName: "node1",
96+
secret: &corev1.Secret{
97+
Data: map[string][]byte{
98+
"address": []byte("redfish+http://192.168.111.1/redfish/v1/Systems/abc"),
99+
"username": []byte("admin"),
100+
"password": []byte("pass123"),
101+
"certificateVerification": []byte("Enabled"),
102+
},
103+
},
104+
wantErr: false,
105+
expectedCfg: &fencingConfig{
106+
NodeName: "node1",
107+
FencingID: "node1_redfish",
108+
FencingDeviceType: "fence_redfish",
109+
FencingDeviceOptions: map[fencingOption]string{
110+
Ip: "192.168.111.1",
111+
IpPort: "80",
112+
SystemsUri: "/redfish/v1/Systems/abc",
113+
Username: "admin",
114+
Password: "pass123",
115+
},
116+
},
117+
},
118+
{
119+
name: "valid redfish config without port number on http ipv6",
120+
nodeName: "node1",
121+
secret: &corev1.Secret{
122+
Data: map[string][]byte{
123+
"address": []byte("redfish+http://[0000:0000:0000::0000]/redfish/v1/Systems/abc"),
124+
"username": []byte("admin"),
125+
"password": []byte("pass123"),
126+
"certificateVerification": []byte("Enabled"),
127+
},
128+
},
129+
wantErr: false,
130+
expectedCfg: &fencingConfig{
131+
NodeName: "node1",
132+
FencingID: "node1_redfish",
133+
FencingDeviceType: "fence_redfish",
134+
FencingDeviceOptions: map[fencingOption]string{
135+
Ip: "0000:0000:0000::0000",
136+
IpPort: "80",
137+
SystemsUri: "/redfish/v1/Systems/abc",
138+
Username: "admin",
139+
Password: "pass123",
140+
},
141+
},
142+
},
68143
{
69144
name: "invalid address format",
70145
nodeName: "node1",
@@ -102,6 +177,18 @@ func TestGetFencingConfig(t *testing.T) {
102177
},
103178
wantErr: true,
104179
},
180+
{
181+
name: "missing port and no schema provided",
182+
nodeName: "node1",
183+
secret: &corev1.Secret{
184+
Data: map[string][]byte{
185+
"address": []byte("192.168.111.1/redfish/v1/Systems/abc"),
186+
"username": []byte("admin"),
187+
"certificateVerification": []byte("Disabled"),
188+
},
189+
},
190+
wantErr: true,
191+
},
105192
}
106193

107194
for _, tt := range tests {

0 commit comments

Comments
 (0)