mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			146 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2016 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package azure_dd
 | |
| 
 | |
| import (
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path"
 | |
| 	"regexp"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/golang/glog"
 | |
| 	"k8s.io/kubernetes/pkg/util/exec"
 | |
| )
 | |
| 
 | |
| type ioHandler interface {
 | |
| 	ReadDir(dirname string) ([]os.FileInfo, error)
 | |
| 	WriteFile(filename string, data []byte, perm os.FileMode) error
 | |
| 	Readlink(name string) (string, error)
 | |
| }
 | |
| 
 | |
| type osIOHandler struct{}
 | |
| 
 | |
| func (handler *osIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) {
 | |
| 	return ioutil.ReadDir(dirname)
 | |
| }
 | |
| func (handler *osIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error {
 | |
| 	return ioutil.WriteFile(filename, data, perm)
 | |
| }
 | |
| func (handler *osIOHandler) Readlink(name string) (string, error) {
 | |
| 	return os.Readlink(name)
 | |
| }
 | |
| 
 | |
| // exclude those used by azure as resource and OS root in /dev/disk/azure
 | |
| func listAzureDiskPath(io ioHandler) []string {
 | |
| 	azureDiskPath := "/dev/disk/azure/"
 | |
| 	var azureDiskList []string
 | |
| 	if dirs, err := io.ReadDir(azureDiskPath); err == nil {
 | |
| 		for _, f := range dirs {
 | |
| 			name := f.Name()
 | |
| 			diskPath := azureDiskPath + name
 | |
| 			if link, linkErr := io.Readlink(diskPath); linkErr == nil {
 | |
| 				sd := link[(strings.LastIndex(link, "/") + 1):]
 | |
| 				azureDiskList = append(azureDiskList, sd)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	glog.V(12).Infof("Azure sys disks paths: %v", azureDiskList)
 | |
| 	return azureDiskList
 | |
| }
 | |
| 
 | |
| // given a LUN find the VHD device path like /dev/sdd
 | |
| // exclude those disks used by Azure resources and OS root
 | |
| func findDiskByLun(lun int, io ioHandler, exe exec.Interface) (string, error) {
 | |
| 	azureDisks := listAzureDiskPath(io)
 | |
| 	return findDiskByLunWithConstraint(lun, io, exe, azureDisks)
 | |
| }
 | |
| 
 | |
| // look for device /dev/sdX and validate it is a VHD
 | |
| // return empty string if no disk is found
 | |
| func findDiskByLunWithConstraint(lun int, io ioHandler, exe exec.Interface, azureDisks []string) (string, error) {
 | |
| 	var err error
 | |
| 	sys_path := "/sys/bus/scsi/devices"
 | |
| 	if dirs, err := io.ReadDir(sys_path); err == nil {
 | |
| 		for _, f := range dirs {
 | |
| 			name := f.Name()
 | |
| 			// look for path like /sys/bus/scsi/devices/3:0:0:1
 | |
| 			arr := strings.Split(name, ":")
 | |
| 			if len(arr) < 4 {
 | |
| 				continue
 | |
| 			}
 | |
| 			// extract LUN from the path.
 | |
| 			// LUN is the last index of the array, i.e. 1 in /sys/bus/scsi/devices/3:0:0:1
 | |
| 			l, err := strconv.Atoi(arr[3])
 | |
| 			if err != nil {
 | |
| 				// unknown path format, continue to read the next one
 | |
| 				glog.Errorf("failed to parse lun from %v (%v), err %v", arr[3], name, err)
 | |
| 				continue
 | |
| 			}
 | |
| 			if lun == l {
 | |
| 				// find the matching LUN
 | |
| 				// read vendor and model to ensure it is a VHD disk
 | |
| 				vendor := path.Join(sys_path, name, "vendor")
 | |
| 				model := path.Join(sys_path, name, "model")
 | |
| 				out, err := exe.Command("cat", vendor, model).CombinedOutput()
 | |
| 				if err != nil {
 | |
| 					glog.Errorf("failed to cat device vendor and model, err: %v", err)
 | |
| 					continue
 | |
| 				}
 | |
| 				matched, err := regexp.MatchString("^MSFT[ ]{0,}\nVIRTUAL DISK[ ]{0,}\n$", strings.ToUpper(string(out)))
 | |
| 				if err != nil || !matched {
 | |
| 					glog.V(4).Infof("doesn't match VHD, output %v, error %v", string(out), err)
 | |
| 					continue
 | |
| 				}
 | |
| 				// find a disk, validate name
 | |
| 				dir := path.Join(sys_path, name, "block")
 | |
| 				if dev, err := io.ReadDir(dir); err == nil {
 | |
| 					found := false
 | |
| 					for _, diskName := range azureDisks {
 | |
| 						glog.V(12).Infof("validating disk %q with sys disk %q", dev[0].Name(), diskName)
 | |
| 						if string(dev[0].Name()) == diskName {
 | |
| 							found = true
 | |
| 							break
 | |
| 						}
 | |
| 					}
 | |
| 					if !found {
 | |
| 						return "/dev/" + dev[0].Name(), nil
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return "", err
 | |
| }
 | |
| 
 | |
| // rescan scsi bus
 | |
| func scsiHostRescan(io ioHandler) {
 | |
| 	scsi_path := "/sys/class/scsi_host/"
 | |
| 	if dirs, err := io.ReadDir(scsi_path); err == nil {
 | |
| 		for _, f := range dirs {
 | |
| 			name := scsi_path + f.Name() + "/scan"
 | |
| 			data := []byte("- - -")
 | |
| 			if err = io.WriteFile(name, data, 0666); err != nil {
 | |
| 				glog.Errorf("failed to rescan scsi host %s", name)
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		glog.Errorf("failed to read %s, err %v", scsi_path, err)
 | |
| 	}
 | |
| }
 |