Skip to content

Commit

Permalink
rbd: parse IP address
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Madhu-1 authored and nixpanic committed Nov 6, 2024
1 parent ce25e16 commit 828c041
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 26 deletions.
52 changes: 27 additions & 25 deletions internal/csi-addons/networkfence/fencing.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}
42 changes: 42 additions & 0 deletions internal/csi-addons/networkfence/fencing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}
12 changes: 11 additions & 1 deletion internal/csi-addons/rbd/network_fence.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
},
},
Expand Down

0 comments on commit 828c041

Please sign in to comment.