rbd: parse IP address

The address we get from ceph
contains the ip in the format
of 10.244.0.1:0/2686266785 we
need to extract the client IP
from this address, we already
have a helper to extract it,
This makes the helper more generic
can be reused by multiple packages
in the fence controller.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna 2024-11-05 11:17:22 +01:00 committed by mergify[bot]
parent facf805941
commit b4592a55eb
3 changed files with 80 additions and 26 deletions

View File

@ -217,31 +217,7 @@ func isIPInCIDR(ctx context.Context, ip, cidr string) bool {
func (ac *activeClient) fetchIP() (string, error) {
// example: "inst": "client.4305 172.21.9.34:0/422650892",
// then returning value will be 172.21.9.34
clientInfo := ac.Inst
// Attempt to extract the IP address using a regular expression
// the regular expression aims to match either a complete IPv6
// address or a complete IPv4 address follows by any prefix (v1 or v2)
// if exists
// (?:v[0-9]+:): this allows for an optional prefix starting with "v"
// followed by one or more digits and a colon.
// The ? outside the group makes the entire prefix section optional.
// (?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}: this allows to check for
// standard IPv6 address.
// |: Alternation operator to allow matching either the IPv6 pattern
// with a prefix or the IPv4 pattern.
// '(?:\d+\.){3}\d+: This part matches a standard IPv4 address.
re := regexp.MustCompile(`(?:v[0-9]+:)?([0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}|(?:\d+\.){3}\d+)`)
ipMatches := re.FindStringSubmatch(clientInfo)
if len(ipMatches) > 0 {
ip := net.ParseIP(ipMatches[1])
if ip != nil {
return ip.String(), nil
}
}
return "", fmt.Errorf("failed to extract IP address, incorrect format: %s", clientInfo)
return ParseClientIP(ac.Inst)
}
func (ac *activeClient) fetchID() (int, error) {
@ -526,3 +502,29 @@ func (nf *NetworkFence) parseBlocklistForCIDR(ctx context.Context, blocklist, ci
return matchingHosts
}
func ParseClientIP(addr string) (string, error) {
// Attempt to extract the IP address using a regular expression
// the regular expression aims to match either a complete IPv6
// address or a complete IPv4 address follows by any prefix (v1 or v2)
// if exists
// (?:v[0-9]+:): this allows for an optional prefix starting with "v"
// followed by one or more digits and a colon.
// The ? outside the group makes the entire prefix section optional.
// (?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}: this allows to check for
// standard IPv6 address.
// |: Alternation operator to allow matching either the IPv6 pattern
// with a prefix or the IPv4 pattern.
// '(?:\d+\.){3}\d+: This part matches a standard IPv4 address.
re := regexp.MustCompile(`(?:v[0-9]+:)?([0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}|(?:\d+\.){3}\d+)`)
ipMatches := re.FindStringSubmatch(addr)
if len(ipMatches) > 0 {
ip := net.ParseIP(ipMatches[1])
if ip != nil {
return ip.String(), nil
}
}
return "", fmt.Errorf("failed to extract IP address, incorrect format: %s", addr)
}

View File

@ -257,3 +257,45 @@ listed 1 entries`,
})
}
}
func TestParseClientIP(t *testing.T) {
t.Parallel()
tests := []struct {
name string
addr string
want string
wantErr bool
}{
{
name: "IPv4 address",
addr: "10.244.0.1:0/2686266785",
want: "10.244.0.1",
wantErr: false,
},
{
name: "IPv6 address",
addr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334:0/2686266785",
want: "2001:db8:85a3::8a2e:370:7334",
wantErr: false,
},
{
name: "Invalid address",
addr: "invalid",
want: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := ParseClientIP(tt.addr)
if (err != nil) != tt.wantErr {
t.Errorf("ParseClientIP() error = %v, wantErr %v", err, tt.wantErr)
}
if got != tt.want {
t.Errorf("ParseClientIP() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -155,13 +155,23 @@ func (fcs *FenceControllerServer) GetFenceClients(
return nil, status.Errorf(codes.Internal, "failed to get client address: %s", err)
}
// The example address we get is 10.244.0.1:0/2686266785 from
// which we need to extract the IP address.
addr, err := nf.ParseClientIP(address)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to parse client address: %s", err)
}
// adding /32 to the IP address to make it a CIDR block.
addr += "/32"
resp := &fence.GetFenceClientsResponse{
Clients: []*fence.ClientDetails{
{
Id: fsID,
Addresses: []*fence.CIDR{
{
Cidr: address,
Cidr: addr,
},
},
},