diff --git a/pkg/server/router.go b/pkg/server/router.go index a789843d5..e3d387f7f 100644 --- a/pkg/server/router.go +++ b/pkg/server/router.go @@ -117,9 +117,9 @@ func getAPIHandler(conf api.Config) (http.Handler, api.Minio) { func getRPCHandler() http.Handler { s := rpc.NewServer() s.RegisterJSONCodec() - s.RegisterService(new(rpc.HelloService), "") s.RegisterService(new(rpc.VersionService), "") s.RegisterService(new(rpc.GetSysInfoService), "") + s.RegisterService(new(rpc.GetDiskInfoService), "") // Add new services here return registerRPC(router.NewRouter(), s) } diff --git a/pkg/server/rpc/diskinfo.go b/pkg/server/rpc/diskinfo.go new file mode 100644 index 000000000..a40c45e53 --- /dev/null +++ b/pkg/server/rpc/diskinfo.go @@ -0,0 +1,58 @@ +/* + * Minimalist Object Storage, (C) 2015 Minio, Inc. + * + * 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 rpc + +import ( + "net/http" + "os" + + "github.com/minio/minio/pkg/iodine" + "github.com/minio/minio/pkg/utils/scsi" +) + +// GetDiskInfoService disk info service +type GetDiskInfoService struct{} + +// GetDiskInfoReply disk info reply for disk info service +type GetDiskInfoReply struct { + Hostname string `json:"hostname"` + Disks []string `json:"disks"` + DiskAttributes map[string]scsi.Attributes `json:"disk-attrs"` +} + +func setDiskInfoReply(sis *GetDiskInfoReply) error { + var err error + sis.Hostname, err = os.Hostname() + if err != nil { + return iodine.New(err, nil) + } + disks, err := scsi.GetDisks() + if err != nil { + return iodine.New(err, nil) + } + sis.DiskAttributes = make(map[string]scsi.Attributes) + for k, v := range disks { + sis.Disks = append(sis.Disks, k) + sis.DiskAttributes[k] = v + } + return nil +} + +// Get method +func (s *GetDiskInfoService) Get(r *http.Request, args *Args, reply *GetDiskInfoReply) error { + return setDiskInfoReply(reply) +} diff --git a/pkg/server/rpc/methods.go b/pkg/server/rpc/sysinfo.go similarity index 60% rename from pkg/server/rpc/methods.go rename to pkg/server/rpc/sysinfo.go index ab7e9a590..e387306f3 100644 --- a/pkg/server/rpc/methods.go +++ b/pkg/server/rpc/sysinfo.go @@ -20,60 +20,9 @@ import ( "net/http" "os" "runtime" - "time" -) - -// HelloArgs - hello args -type HelloArgs struct { - Who string -} - -// HelloReply - hello reply -type HelloReply struct { - Message string -} - -// HelloService - hello service -type HelloService struct{} - -// Say method -func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error { - reply.Message = "Hello, " + args.Who + "!" - return nil -} - -// Args basic json RPC params -type Args struct { - Request string -} - -// VersionReply version reply -type VersionReply struct { - Version string `json:"version"` - BuildDate string `json:"build-date"` -} - -// VersionService - -type VersionService struct{} - -func getVersion() string { - return "0.0.1" -} -func getBuildDate() string { - return time.Now().UTC().Format(http.TimeFormat) -} - -func setVersionReply(reply *VersionReply) { - reply.Version = getVersion() - reply.BuildDate = getBuildDate() - return -} -// Get method -func (v *VersionService) Get(r *http.Request, args *Args, reply *VersionReply) error { - setVersionReply(reply) - return nil -} + "github.com/minio/minio/pkg/iodine" +) // GetSysInfoService - type GetSysInfoService struct{} @@ -95,7 +44,12 @@ func setSysInfoReply(sis *GetSysInfoReply) error { sis.SysCPUS = runtime.NumCPU() sis.Routines = runtime.NumGoroutine() sis.GOVersion = runtime.Version() - sis.Hostname, _ = os.Hostname() + + var err error + sis.Hostname, err = os.Hostname() + if err != nil { + return iodine.New(err, nil) + } var memStats runtime.MemStats runtime.ReadMemStats(&memStats) diff --git a/pkg/server/rpc/version.go b/pkg/server/rpc/version.go new file mode 100644 index 000000000..7ced393eb --- /dev/null +++ b/pkg/server/rpc/version.go @@ -0,0 +1,55 @@ +/* + * Minimalist Object Storage, (C) 2015 Minio, Inc. + * + * 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 rpc + +import ( + "net/http" + "time" +) + +// Args basic json RPC params +type Args struct { + Request string +} + +// VersionReply version reply +type VersionReply struct { + Version string `json:"version"` + BuildDate string `json:"build-date"` +} + +// VersionService - +type VersionService struct{} + +func getVersion() string { + return "0.0.1" +} +func getBuildDate() string { + return time.Now().UTC().Format(http.TimeFormat) +} + +func setVersionReply(reply *VersionReply) { + reply.Version = getVersion() + reply.BuildDate = getBuildDate() + return +} + +// Get method +func (v *VersionService) Get(r *http.Request, args *Args, reply *VersionReply) error { + setVersionReply(reply) + return nil +} diff --git a/pkg/server/server.go b/pkg/server/server.go index 999c36efe..220f7f337 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -22,6 +22,7 @@ import ( "net/http" "strings" + "github.com/minio/minio/pkg/iodine" "github.com/minio/minio/pkg/server/api" ) @@ -38,7 +39,7 @@ func startAPI(errCh chan error, conf api.Config, apiHandler http.Handler) { host, port, err := net.SplitHostPort(conf.Address) if err != nil { - errCh <- err + errCh <- iodine.New(err, nil) return } @@ -49,7 +50,7 @@ func startAPI(errCh chan error, conf api.Config, apiHandler http.Handler) { default: addrs, err := net.InterfaceAddrs() if err != nil { - errCh <- err + errCh <- iodine.New(err, nil) return } for _, addr := range addrs { @@ -109,8 +110,8 @@ func StartServices(conf api.Config) error { select { case err := <-apiErrCh: - return err + return iodine.New(err, nil) case err := <-rpcErrCh: - return err + return iodine.New(err, nil) } } diff --git a/pkg/utils/scsi/constants.go b/pkg/utils/scsi/constants.go new file mode 100644 index 000000000..6a13b0ff1 --- /dev/null +++ b/pkg/utils/scsi/constants.go @@ -0,0 +1,66 @@ +// +build linux,amd64 + +/* + * Mini Object Storage, (C) 2014 Minio, Inc. + * + * 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 scsi + +// System sysfs constants +const ( + // From 2.6.x kernel onwards, no need to support procfs + sysFSROOT = "/sys" + sysFSDEVICES = "/sys/bus/scsi/devices" + sysFSBLOCK = "/block" + sysFSCLASSSCSIDEVICES = "/sys/class/scsi_device" + udev = "/dev" + devDISKBYID = "/dev/disk/by-id" +) + +// ScsiDEVICETYPES list of various scsi devices +var ScsiDEVICETYPES = []string{ + "disk", + "tape", + "printer", + "process", + "worm", + "cd/dvd", + "scanner", + "optical", + "mediumx", + "comms", + "(0xa)", + "(0xb)", + "storage", + "enclosu", + "sim disk", + "optical rd", + "bridge", + "osd", + "adi", + "sec man", + "zbc", + "(0x15)", + "(0x16)", + "(0x17)", + "(0x18)", + "(0x19)", + "(0x1a)", + "(0x1b)", + "(0x1c)", + "(0x1e)", + "wlun", + "no dev", +} diff --git a/pkg/utils/scsi/scsi-common.go b/pkg/utils/scsi/scsi-common.go new file mode 100644 index 000000000..816844513 --- /dev/null +++ b/pkg/utils/scsi/scsi-common.go @@ -0,0 +1,48 @@ +// +build linux,amd64 + +/* + * Mini Object Storage, (C) 2014 Minio, Inc. + * + * 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 scsi + +import ( + "io/ioutil" + "os" + "path" + "strings" +) + +func getattrs(scsiAttrPath string, scsiAttrList []string) map[string]string { + attrMap := make(map[string]string) + for _, attr := range scsiAttrList { + value, _ := ioutil.ReadFile(path.Join(scsiAttrPath, attr)) + attrMap[attr] = strings.Trim(string(value[:]), "\n") // remove odd newlines + } + return attrMap +} + +func filterdisks(files []os.FileInfo) (scsidisks []string) { + for _, fi := range files { + if strings.Contains(fi.Name(), "host") { + continue + } + if strings.Contains(fi.Name(), "target") { + continue + } + scsidisks = append(scsidisks, fi.Name()) + } + return scsidisks +} diff --git a/pkg/utils/scsi/scsi.go b/pkg/utils/scsi/scsi.go new file mode 100644 index 000000000..b80d96428 --- /dev/null +++ b/pkg/utils/scsi/scsi.go @@ -0,0 +1,101 @@ +// +build linux,amd64 + +/* + * Minimalist Object Storage, (C) 2015 Minio, Inc. + * + * 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 scsi + +import ( + "errors" + "io/ioutil" + "path/filepath" + + "github.com/minio/minio/pkg/iodine" +) + +// NOTE : supporting virtio based scsi devices is out of scope for this implementation + +// Attributes Scsi device attributes +type Attributes map[string]string + +// Disks is a list of scsis disks and attributes +type Disks map[string]Attributes + +// Get get disk scsi params +func (d Disks) Get(disk string) Attributes { + return d[disk] +} + +// Len return len of total disks +func (d Disks) Len() int { + return len(d) +} + +// GetDisks - get system devices list +func GetDisks() (Disks, error) { + var scsidevices []string + var scsiAttrList []string + d := Disks{} + + sysFiles, err := ioutil.ReadDir(sysFSDEVICES) + if err != nil { + return Disks{}, iodine.New(err, nil) + } + + scsidevices = filterdisks(sysFiles) + if len(scsidevices) == 0 { + // may be a docker instance, ignore this + return Disks{}, nil + } + + for _, s := range scsidevices { + scsiAttrPath := filepath.Join(sysFSDEVICES, s) + scsiAttrs, err := ioutil.ReadDir(scsiAttrPath) + if err != nil { + return Disks{}, iodine.New(err, nil) + } + scsiBlockPath := filepath.Join(sysFSDEVICES, s, sysFSBLOCK) + scsidevList, err := ioutil.ReadDir(scsiBlockPath) + if err != nil { + return Disks{}, iodine.New(err, nil) + } + if len(scsidevList) > 1 { + return Disks{}, iodine.New(errors.New("Scsi address points to multiple block devices"), nil) + } + device := filepath.Join(udev, scsidevList[0].Name()) + for _, sa := range scsiAttrs { + // Skip directories + if sa.IsDir() { + continue + } + // Skip symlinks + if !sa.Mode().IsRegular() { + continue + } + // Skip, not readable, write-only + if sa.Mode().Perm() == 128 { + continue + } + scsiAttrList = append(scsiAttrList, sa.Name()) + } + + if len(scsiAttrList) == 0 { + return Disks{}, iodine.New(errors.New("No scsi attributes found"), nil) + } + d[device] = getattrs(scsiAttrPath, scsiAttrList) + } + return d, nil +} diff --git a/pkg/utils/scsi/scsi_test.go b/pkg/utils/scsi/scsi_test.go new file mode 100644 index 000000000..e8086a554 --- /dev/null +++ b/pkg/utils/scsi/scsi_test.go @@ -0,0 +1,36 @@ +// +build linux,amd64 + +/* + * Minimalist Object Storage, (C) 2015 Minio, Inc. + * + * 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 scsi + +import ( + "testing" + + . "github.com/minio/check" +) + +type MySuite struct{} + +var _ = Suite(&MySuite{}) + +func Test(t *testing.T) { TestingT(t) } + +func (s *MySuite) TestSCSI(c *C) { + _, err := GetDisks() + c.Assert(err, IsNil) +}