diff --git a/go.mod b/go.mod index 71a148d1..3a2f22ab 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Scalingo/go-etcd-lock/v5 v5.0.8 github.com/container-storage-interface/spec v1.7.0 github.com/golang/protobuf v1.5.4 - github.com/hpe-storage/common-host-libs v0.0.0-20251211043240-048259886829 + github.com/hpe-storage/common-host-libs v0.0.0-20251219113026-a2b01022e639 github.com/hpe-storage/k8s-custom-resources v0.0.0-20251212042708-ffa3e0c9c7d3 github.com/kubernetes-csi/csi-lib-utils v0.11.0 github.com/kubernetes-csi/csi-test v2.2.0+incompatible diff --git a/go.sum b/go.sum index b733dcea..fe283030 100644 --- a/go.sum +++ b/go.sum @@ -273,8 +273,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hpe-storage/common-host-libs v0.0.0-20251211043240-048259886829 h1:zWa7Rg3yU/mPdzP5UDzRBq9HnZ4dHiVfY/8XGz2jrag= -github.com/hpe-storage/common-host-libs v0.0.0-20251211043240-048259886829/go.mod h1:LtFiruLqjTXLJ5TfFAYDEgSja5oW0rey5D1fSBTe2OY= +github.com/hpe-storage/common-host-libs v0.0.0-20251219113026-a2b01022e639 h1:fRJdyJyipF3wSu/izrYFYZY6p05YF8cp0YfnduWbQ0g= +github.com/hpe-storage/common-host-libs v0.0.0-20251219113026-a2b01022e639/go.mod h1:LtFiruLqjTXLJ5TfFAYDEgSja5oW0rey5D1fSBTe2OY= github.com/hpe-storage/k8s-custom-resources v0.0.0-20251212042708-ffa3e0c9c7d3 h1:Uhdao8BivRfby+dYL8gRWQ8AegQZxJXIknGHI75IGq0= github.com/hpe-storage/k8s-custom-resources v0.0.0-20251212042708-ffa3e0c9c7d3/go.mod h1:+zrGrGKf/jqr38KxLEGRll+UsjeUybdLH0MZCBxPPoI= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/device.go b/vendor/github.com/hpe-storage/common-host-libs/linux/device.go index e76cd340..629f2818 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/device.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/device.go @@ -503,6 +503,7 @@ func isLuksDevice(devPath string) (bool, error) { func createLinuxDevice(volume *model.Volume) (dev *model.Device, err error) { log.Debugf(">>>> createLinuxDevice called with volume %s serialNumber %s and lunID %s", volume.Name, volume.SerialNumber, volume.LunID) defer log.Debug("<<<<< createLinuxDevice") + // Handle NVMe/TCP device creation if strings.EqualFold(volume.AccessProtocol, "nvmetcp") { log.Tracef("NVMe/TCP requested, NQN: %s, Serial: %s", volume.Nqn, volume.SerialNumber) @@ -515,14 +516,14 @@ func createLinuxDevice(volume *model.Volume) (dev *model.Device, err error) { // Attempt to locate NVMe device by NQN or Serial nvmeDev, lookupErr := GetNvmeDeviceFromNamespace(volume.Nqn) if lookupErr == nil && nvmeDev != nil { - // Populate NVMe targets - nvmeDev.NvmeTargets = []*model.NvmeTarget{ - { - NQN: volume.Nqn, - Address: volume.TargetAddress, - Port: volume.TargetPort, - }, - } + // Populate NVMe targets + nvmeDev.NvmeTargets = []*model.NvmeTarget{ + { + NQN: volume.Nqn, + Address: volume.TargetAddress, + Port: volume.TargetPort, + }, + } log.Infof("NVMe/TCP device found: %+v", nvmeDev) return nvmeDev, nil } diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/initiator.go b/vendor/github.com/hpe-storage/common-host-libs/linux/initiator.go index eed2e170..ac952e24 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/initiator.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/initiator.go @@ -15,8 +15,8 @@ var ( initiatorNamePattern = "^InitiatorName=(?P.*)$" iscsi = "iscsi" fc = "fc" - nvmeHostnqnPath = "/etc/nvme/hostnqn" - nvmeHostnqnPattern = "^(?Pnqn\\..*)$" + nvmeHostnqnPath = "/etc/nvme/hostnqn" + nvmeHostnqnPattern = "^(?Pnqn\\..*)$" nvmeotcp = "nvmeotcp" ) diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/iscsi.go b/vendor/github.com/hpe-storage/common-host-libs/linux/iscsi.go index 69506bc5..441fc21a 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/iscsi.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/iscsi.go @@ -63,7 +63,7 @@ var ( targetVendorPatterns = []string{"com.nimblestorage", "com.3pardata", "org.truenas.ctl", "org.freenas.ctl", "com.hpe"} ) -//type of Scope (volume, group) +// type of Scope (volume, group) type targetScope int const ( @@ -312,8 +312,29 @@ func loginToTarget(targets model.IscsiTargets, targetIqn string, ifaces []*model return nil } +// formatIPWithPort formats an IP address with port, using brackets for IPv6 +func formatIPWithPort(ip string, port int) string { + parsedIP := net.ParseIP(ip) + if parsedIP == nil { + // Invalid IP, return as-is with port + log.Warnf("Invalid IP address format: %s", ip) + return fmt.Sprintf("%s:%d", ip, port) + } + + // Check if IPv4 using To4() + ipv4 := parsedIP.To4() + if ipv4 != nil { + // IPv4 address - return without brackets + return fmt.Sprintf("%s:%d", ip, port) + } + + // IPv6 address - return with brackets + return fmt.Sprintf("[%s]:%d", ip, port) +} + func isReachable(initiatorIP, targetIP string) (reachable bool, err error) { // Allocate a new ICMP ping object + targetIP = util.SanitizeIPAddress(targetIP) pinger, err := ping.NewPinger(targetIP) if err != nil { log.Errorf("NewPinger creation failure, err=%v", err) @@ -353,9 +374,11 @@ func isReachable(initiatorIP, targetIP string) (reachable bool, err error) { local := &net.TCPAddr{IP: net.ParseIP(initiatorIP)} dialer := net.Dialer{Timeout: PingTimeout, LocalAddr: local} - _, err = dialer.Dial("tcp", fmt.Sprintf("%s:%d", targetIP, DefaultIscsiPort)) + // Format target address with bracket notation for IPv6 + targetAddr := formatIPWithPort(targetIP, DefaultIscsiPort) + _, err = dialer.Dial("tcp", targetAddr) if err != nil { - log.Warnf("TCP connection attempt failed %s --> (%s:%d), err %s", initiatorIP, targetIP, DefaultIscsiPort, err.Error()) + log.Warnf("TCP connection attempt failed %s --> (%s), err %s", initiatorIP, targetAddr, err.Error()) return false, nil } } @@ -436,15 +459,25 @@ func addTarget(target *model.IscsiTarget, ifaces []*model.Iface, chapUser, chapP if len(ifaces) > 0 { for _, iface := range ifaces { + // Select source IP based on target IP type (IPv4 or IPv6) + sourceIP := iface.NetworkInterface.AddressV4 + if net.ParseIP(target.Address).To4() == nil && iface.NetworkInterface.AddressV6 != "" { + // Target is IPv6, use IPv6 source address + sourceIP = iface.NetworkInterface.AddressV6 + } + // Skip if source IP is empty + if sourceIP == "" { + continue + } // verify if the target is reachable from this interface - reachable, err := isReachable(iface.NetworkInterface.AddressV4, target.Address) + reachable, err := isReachable(sourceIP, target.Address) if err != nil { - log.Warnf("failed to run ping test from %s --> (%s)", iface.NetworkInterface.AddressV4, target.Address) + log.Warnf("failed to run ping test from %s --> (%s)", sourceIP, target.Address) // if we cannot issue ping for some reason, proceed with iscsi login reachable = true } if !reachable { - log.Errorf("ping test failed from %s --> (%s), skipping iscsi login on this portal to %s", iface.NetworkInterface.AddressV4, target.Address, target.Name) + log.Errorf("ping test failed from %s --> (%s), skipping iscsi login on this portal to %s", sourceIP, target.Address, target.Name) continue } // login using each iface bound @@ -728,9 +761,11 @@ func GetIscsiNodesFromIsciadm() (a model.IscsiTargets, err error) { listOut := r.FindAllString(outItem, -1) for _, line := range listOut { result := util.FindStringSubmatchMap(line, r) + // Strip brackets from IPv6 addresses + address := util.SanitizeIPAddress(result["address"]) target := &model.IscsiTarget{ Name: result["target"], - Address: result["address"], + Address: address, Port: result["port"], } log.Tracef("Name %s Address %s Port %s", target.Name, target.Address, target.Port) @@ -755,6 +790,7 @@ func PerformDiscovery(discoveryIPs []string) (a model.IscsiTargets, err error) { var outList []string for _, discoveryIP := range discoveryIPs { // find the first discovery ip which is reachable + discoveryIP = util.SanitizeIPAddress(discoveryIP) isDiscoveryIpReachable, err = isReachable("", discoveryIP) if err != nil { continue @@ -788,9 +824,11 @@ func PerformDiscovery(discoveryIPs []string) (a model.IscsiTargets, err error) { listOut := r.FindAllString(outItem, -1) for _, line := range listOut { result := util.FindStringSubmatchMap(line, r) + // Strip brackets from IPv6 addresses + address := util.SanitizeIPAddress(result["address"]) target := &model.IscsiTarget{ Name: result["target"], - Address: result["address"], + Address: address, Port: result["port"], } log.Tracef("Name %s Address %s Port %s", target.Name, target.Address, target.Port) @@ -856,8 +894,7 @@ func iscsiGetTargetsOfDevice(dev *model.Device) (target []*model.IscsiTarget, er } } return iscsiTargets, nil - - + } func getIscsiTargetFromSessionID(dev *model.Device, host string, sessionID string) (*model.IscsiTarget, error) { @@ -1069,7 +1106,9 @@ func addIscsiPortBinding(networks []*model.NetworkInterface) error { // returns iface matching the network address specified or nil otherwise func getMatchingIface(ifaces []*model.Iface, network *model.NetworkInterface) (iface *model.Iface) { for _, iface := range ifaces { - if network.AddressV4 == iface.NetworkInterface.AddressV4 { + if network.AddressV4 == iface.NetworkInterface.AddressV4 && network.AddressV4 != "" { + return iface + } else if network.AddressV6 == iface.NetworkInterface.AddressV6 && network.AddressV6 != "" { return iface } } diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/mount.go b/vendor/github.com/hpe-storage/common-host-libs/linux/mount.go index 0a1b9b04..1f1c4129 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/mount.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/mount.go @@ -432,6 +432,7 @@ func UnmountFileSystem(mountPoint string) (*model.Mount, error) { } return mnt, nil } + func IsLastNamespaceForNQN(nqn string) bool { files, err := ioutil.ReadDir(nvmeClassDir) if err != nil { @@ -477,8 +478,8 @@ func UnmountDevice(device *model.Device, mountPoint string) (*model.Mount, error } mount, err := UnmountFileSystem(mountPoint) if err != nil { - return mount, err - } + return mount, err + } // Disconnect and delete NVMe subsystem after unmount log.Debugf("Nvme targets %v+", device.NvmeTargets) if device.NvmeTargets != nil && len(device.NvmeTargets) > 0 { diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/network.go b/vendor/github.com/hpe-storage/common-host-libs/linux/network.go index d5328355..675db72c 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/network.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/network.go @@ -149,28 +149,51 @@ func getNetworkInterfaces() ([]*model.NetworkInterface, error) { } for _, addr := range addrs { networkIp, ok := addr.(*net.IPNet) - if ok && !networkIp.IP.IsLoopback() && networkIp.IP.To4() != nil && networkIp.Mask != nil { - mask := networkIp.Mask - if len(mask) != 4 { - // continue with other addresses - continue + if ok && !networkIp.IP.IsLoopback() { + if networkIp.IP.To4() != nil && networkIp.Mask != nil { + mask := networkIp.Mask + if len(mask) != 4 { + // continue with other addresses + continue + } + nic := &model.NetworkInterface{ + Name: i.Name, + AddressV4: networkIp.IP.To4().String(), + MaskV4: fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]), + Mtu: int64(i.MTU), + Mac: i.HardwareAddr.String(), + CidrNetwork: addr.String(), + } + if strings.Contains(i.Flags.String(), "up") { + nic.Up = true + } else { + nic.Up = false + } + log.Infof("Found IPv4 network interface %s with address %s", nic.Name, nic.AddressV4) + nics = append(nics, nic) + } else if networkIp.IP.To16() != nil && networkIp.Mask != nil { + mask := networkIp.Mask + if len(mask) != 16 { + // continue with other addresses + continue + } + nic := &model.NetworkInterface{ + Name: i.Name, + AddressV6: networkIp.IP.To16().String(), + MaskV6: net.IP(mask).String(), + Mtu: int64(i.MTU), + Mac: i.HardwareAddr.String(), + CidrNetwork: addr.String(), + } + if strings.Contains(i.Flags.String(), "up") { + nic.Up = true + } else { + nic.Up = false + } + log.Infof("Found IPv6 network interface %s with address %s", nic.Name, nic.AddressV6) + nics = append(nics, nic) } - nic := &model.NetworkInterface{ - Name: i.Name, - AddressV4: networkIp.IP.To4().String(), - MaskV4: fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]), - Mtu: int64(i.MTU), - Mac: i.HardwareAddr.String(), - CidrNetwork: addr.String(), - } - if strings.Contains(i.Flags.String(), "up") { - nic.Up = true - } else { - nic.Up = false - } - nics = append(nics, nic) } - } } return nics, nil diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/nvme.go b/vendor/github.com/hpe-storage/common-host-libs/linux/nvme.go index fb220b12..2470f7ad 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/nvme.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/nvme.go @@ -146,7 +146,7 @@ func HandleNvmeTcpDiscovery(volume *model.Volume) error { // 2. Prepare NVMe target info target := &model.NvmeTarget{ NQN: volume.Nqn, - Address: strings.Join(volume.DiscoveryIPs, ","), + Address: volume.TargetAddress, Port: volume.TargetPort, } diff --git a/vendor/github.com/hpe-storage/common-host-libs/linux/types.go b/vendor/github.com/hpe-storage/common-host-libs/linux/types.go index 52107357..db35aefa 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/linux/types.go +++ b/vendor/github.com/hpe-storage/common-host-libs/linux/types.go @@ -47,4 +47,5 @@ const ( nvmeClassDir = "/sys/class/nvme/" netCoreRmemMax = "16777216" // in bytes netCoreWmemMax = "16777216" // in bytes + ) diff --git a/vendor/github.com/hpe-storage/common-host-libs/model/types.go b/vendor/github.com/hpe-storage/common-host-libs/model/types.go index 456b7f35..2aa8a140 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/model/types.go +++ b/vendor/github.com/hpe-storage/common-host-libs/model/types.go @@ -116,6 +116,8 @@ type NetworkInterface struct { Name string `json:"name,omitempty"` AddressV4 string `json:"address_v4,omitempty"` MaskV4 string `json:"mask_v4,omitempty"` + AddressV6 string `json:"address_v6,omitempty"` + MaskV6 string `json:"mask_v6,omitempty"` BroadcastV4 string `json:",omitempty"` Mac string `json:",omitempty"` Mtu int64 `json:",omitempty"` diff --git a/vendor/github.com/hpe-storage/common-host-libs/util/strings.go b/vendor/github.com/hpe-storage/common-host-libs/util/strings.go index eb7899cb..11d88b1b 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/util/strings.go +++ b/vendor/github.com/hpe-storage/common-host-libs/util/strings.go @@ -55,3 +55,15 @@ func GetMD5HashOfTwoStrings(string1, string2 string) string { io.WriteString(h, string1+string2) return hex.EncodeToString(h.Sum(nil)) } + +// SanitizeIPAddress removes any character from the input string that is not +// a valid character for either IPv4 or IPv6 addresses. +// Valid characters are: 0-9, a-f, A-F, ., : +func SanitizeIPAddress(ip string) string { + const invalidCharsRegex = "[^0-9a-fA-F.:]" + var ipCleaner = regexp.MustCompile(invalidCharsRegex) + if ip != "" { + return ipCleaner.ReplaceAllString(ip, "") + } + return ip +} diff --git a/vendor/github.com/hpe-storage/common-host-libs/util/volume.go b/vendor/github.com/hpe-storage/common-host-libs/util/volume.go index f8a57616..3a9d1d7d 100644 --- a/vendor/github.com/hpe-storage/common-host-libs/util/volume.go +++ b/vendor/github.com/hpe-storage/common-host-libs/util/volume.go @@ -4,7 +4,6 @@ package util import ( "encoding/json" - "github.com/hpe-storage/common-host-libs/logger" "github.com/hpe-storage/common-host-libs/model" ) diff --git a/vendor/github.com/hpe-storage/k8s-custom-resources/pkg/apis/hpestorage/v1/types.go b/vendor/github.com/hpe-storage/k8s-custom-resources/pkg/apis/hpestorage/v1/types.go index 4d0e0bc0..23c40649 100644 --- a/vendor/github.com/hpe-storage/k8s-custom-resources/pkg/apis/hpestorage/v1/types.go +++ b/vendor/github.com/hpe-storage/k8s-custom-resources/pkg/apis/hpestorage/v1/types.go @@ -28,11 +28,9 @@ type HPENodeInfoList struct { // HPENodeInfoSpec defines the properties listed on an HPENodeInfo type HPENodeInfoSpec struct { - UUID string `json:"uuid"` - IQNs []string `json:"iqns,omitempty"` - Networks []string `json:"networks,omitempty"` - WWPNs []string `json:"wwpns,omitempty"` - NQNs []string `json:"nqns,omitempty"` - ChapUser string `json:"chapUser,omitempty"` - ChapPassword string `json:"chapPassword,omitempty"` + UUID string `json:"uuid"` + IQNs []string `json:"iqns,omitempty"` + Networks []string `json:"networks,omitempty"` + WWPNs []string `json:"wwpns,omitempty"` + NQNs []string `json:"nqns,omitempty"` } diff --git a/vendor/modules.txt b/vendor/modules.txt index 460d437d..90f68748 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -89,7 +89,7 @@ github.com/google/uuid # github.com/gorilla/mux v1.8.0 ## explicit; go 1.12 github.com/gorilla/mux -# github.com/hpe-storage/common-host-libs v0.0.0-20251211043240-048259886829 +# github.com/hpe-storage/common-host-libs v0.0.0-20251219113026-a2b01022e639 ## explicit; go 1.23.0 github.com/hpe-storage/common-host-libs/chapi github.com/hpe-storage/common-host-libs/concurrent