Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DAOS-16127 tools: Add daos health check command (#14730) #14885

Merged
merged 3 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/client/api/SConscript
mjmac marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Build DAOS client"""

LIBDAOS_SRC = ['agent.c', 'array.c', 'container.c', 'event.c', 'init.c', 'job.c', 'kv.c', 'mgmt.c',
'object.c', 'pool.c', 'rpc.c', 'task.c', 'tx.c', 'pipeline.c', 'metrics.c']
'object.c', 'pool.c', 'rpc.c', 'task.c', 'tx.c', 'pipeline.c', 'metrics.c',
'version.c']


def scons():
Expand Down
31 changes: 31 additions & 0 deletions src/client/api/version.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* (C) Copyright 2024 Intel Corporation.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
/**
* This file is part of daos
*
* src/client/api/version.c
*/
#define D_LOGFAC DD_FAC(client)

#include <daos/common.h>
#include <daos_version.h>

/**
* Retrieve DAOS client API version.
*/
int
daos_version_get(int *major, int *minor, int *fix)
{
if (major == NULL || minor == NULL || fix == NULL) {
D_ERROR("major, minor, fix must not be NULL\n");
return -DER_INVAL;
}
*major = DAOS_API_VERSION_MAJOR;
*minor = DAOS_API_VERSION_MINOR;
*fix = DAOS_API_VERSION_FIX;

return 0;
}
6 changes: 4 additions & 2 deletions src/control/build/interop.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2022 Intel Corporation.
// (C) Copyright 2022-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand Down Expand Up @@ -40,6 +40,8 @@ var (
ComponentAdmin = Component("admin")
// ComponentAgent represents the compute node agent.
ComponentAgent = Component("agent")
// ComponentClient represents the libdaos client.
ComponentClient = Component("client")
)

// NewVersionedComponent creates a new VersionedComponent.
Expand All @@ -50,7 +52,7 @@ func NewVersionedComponent(comp Component, version string) (*VersionedComponent,
}

switch comp {
case ComponentServer, ComponentAdmin, ComponentAgent, ComponentAny:
case ComponentServer, ComponentAdmin, ComponentAgent, ComponentClient, ComponentAny:
return &VersionedComponent{
Component: comp,
Version: v,
Expand Down
227 changes: 227 additions & 0 deletions src/control/build/lib_versions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
//
// (C) Copyright 2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//

package build

import (
"bufio"
"fmt"
"io"
"os"
"regexp"
"strings"

"github.com/pkg/errors"

"github.com/daos-stack/daos/src/control/lib/dlopen"
)

/*
#include <stdint.h>

int
get_fi_version(void *fn, int *major, int *minor, int *patch)
{
uint32_t version;

if (fn == NULL || major == NULL || minor == NULL || patch == NULL) {
return -1;
}
// uint32_t fi_version(void);
version = ((uint32_t (*)(void))fn)();

if (version == 0) {
return -1;
}

// FI_MAJOR(version);
*major = (version >> 16);
// FI_MINOR(version);
*minor = (version & 0xFFFF);
// No way to get at revision number via ABI. :(

return 0;
}

int
get_hg_version(void *fn, int *major, int *minor, int *patch)
{
if (fn == NULL || major == NULL || minor == NULL || patch == NULL) {
return -1;
}
// int HG_Version_get(int *, int *, int *);
return ((int (*)(int *, int *, int *))fn)(major, minor, patch);
}

int
get_daos_version(void *fn, int *major, int *minor, int *fix)
{
if (fn == NULL || major == NULL || minor == NULL || fix == NULL) {
return -1;
}
// int daos_version_get(int *, int *, int *);
return ((int (*)(int *, int *, int *))fn)(major, minor, fix);
}
*/
import "C"

// readMappedLibPath attempts to resolve the given library name to an on-disk path.
// NB: The library must be loaded in order for it to be found!
func readMappedLibPath(input io.Reader, libName string) (string, error) {
if libName == "" {
return "", nil
}

libs := make(map[string]struct{})
libRe := regexp.MustCompile(fmt.Sprintf(`\s([^\s]+/%s[\-\.\d]*\.so.*$)`, libName))
scanner := bufio.NewScanner(input)
for scanner.Scan() {
if matches := libRe.FindStringSubmatch(scanner.Text()); len(matches) > 1 {
libs[matches[1]] = struct{}{}
}
}

if len(libs) == 0 {
return "", errors.Errorf("unable to find path for %q", libName)
} else if len(libs) > 1 {
return "", errors.Errorf("multiple paths found for %q: %v", libName, libs)
}

var libPath string
for lib := range libs {
libPath = lib
break
}
return libPath, nil
}

func getLibPath(libName string) (string, error) {
f, err := os.Open("/proc/self/maps")
if err != nil {
return "", errors.Wrapf(err, "failed to open %s", "/proc/self/maps")
}
defer f.Close()

return readMappedLibPath(f, libName)
}

func getLibHandle(libName string) (string, *dlopen.LibHandle, error) {
searchLib := libName + ".so"

// Check to see if it's already loaded, and if so, use that path
// instead of searching in order to make sure we're getting a
// handle to the correct library.
libPath, _ := getLibPath(libName)
if libPath != "" {
searchLib = libPath
}

hdl, err := dlopen.GetHandle(searchLib)
if err != nil {
return "", nil, err
}

if libPath == "" {
libPath, err = getLibPath(libName)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to get path for %q: %+v\n", libName, err)
return "", nil, err
}
}

return libPath, hdl, err
}

func getLibFabricVersion() (*Version, string, error) {
libPath, hdl, err := getLibHandle("libfabric")
if err != nil {
return nil, "", err
}
defer hdl.Close()

ptr, err := hdl.GetSymbolPointer("fi_version")
if err != nil {
return nil, "", err
}

var major, minor, patch C.int
rc := C.get_fi_version(ptr, &major, &minor, &patch)
if rc != 0 {
return nil, "", errors.Errorf("get_fi_version() failed: %d", rc)
}

return &Version{
Major: int(major),
Minor: int(minor),
Patch: int(patch),
}, libPath, nil
}

func getMercuryVersion() (*Version, string, error) {
libPath, hdl, err := getLibHandle("libmercury")
if err != nil {
return nil, "", err
}
defer hdl.Close()

ptr, err := hdl.GetSymbolPointer("HG_Version_get")
if err != nil {
return nil, "", err
}

var major, minor, patch C.int
rc := C.get_hg_version(ptr, &major, &minor, &patch)
if rc != 0 {
return nil, "", errors.Errorf("get_hg_version() failed: %d", rc)
}

return &Version{
Major: int(major),
Minor: int(minor),
Patch: int(patch),
}, libPath, nil
}

func getDAOSVersion() (*Version, string, error) {
libPath, hdl, err := getLibHandle("libdaos")
if err != nil {
return nil, "", err
}
defer hdl.Close()

ptr, err := hdl.GetSymbolPointer("daos_version_get")
if err != nil {
return nil, "", err
}

var major, minor, fix C.int
rc := C.get_daos_version(ptr, &major, &minor, &fix)
if rc != 0 {
return nil, "", errors.Errorf("get_daos_version() failed: %d", rc)
}

return &Version{
Major: int(major),
Minor: int(minor),
Patch: int(fix),
}, libPath, nil
}

// GetLibraryInfo attempts to resolve the given library name into a version and path.
// NB: The library must provide an ABI method to obtain its version, and that
// method needs to be added to this package in order to support it.
func GetLibraryInfo(libName string) (*Version, string, error) {
switch strings.TrimPrefix(strings.ToLower(libName), "lib") {
case "fabric":
return getLibFabricVersion()
case "mercury":
return getMercuryVersion()
case "daos":
return getDAOSVersion()
default:
return nil, "", errors.Errorf("unsupported library: %q", libName)
}
}
87 changes: 87 additions & 0 deletions src/control/build/lib_versions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// (C) Copyright 2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//

package build

import (
"io"
"strings"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"

"github.com/daos-stack/daos/src/control/common/test"
)

func TestBuild_readMappedLibPath(t *testing.T) {
testMap := `
55a05b000000-55a05b008000 r-xp 00000000 fd:01 44060915 /usr/bin/cat
55a05b207000-55a05b208000 r--p 00007000 fd:01 44060915 /usr/bin/cat
55a05b208000-55a05b209000 rw-p 00008000 fd:01 44060915 /usr/bin/cat
55a05d1d5000-55a05d1f6000 rw-p 00000000 00:00 0 [heap]
7f2126a00000-7f2126bcd000 r-xp 00000000 fd:01 44043909 /usr/lib64/libc-2.28.so
7f2126bcd000-7f2126dcc000 ---p 001cd000 fd:01 44043909 /usr/lib64/libc-2.28.so
7f2126dcc000-7f2126dd0000 r--p 001cc000 fd:01 44043909 /usr/lib64/libc-2.28.so
7f2126dd0000-7f2126dd2000 rw-p 001d0000 fd:01 44043909 /usr/lib64/libc-2.28.so
7f2126dd2000-7f2126dd6000 rw-p 00000000 00:00 0
7f2126e00000-7f2126e2f000 r-xp 00000000 fd:01 44043895 /usr/lib64/ld-2.28.so
7f212702f000-7f2127030000 r--p 0002f000 fd:01 44043895 /usr/lib64/ld-2.28.so
7f2127030000-7f2127032000 rw-p 00030000 fd:01 44043895 /usr/lib64/ld-2.28.so
7f2127135000-7f212715a000 rw-p 00000000 00:00 0
7f2127162000-7f2127164000 rw-p 00000000 00:00 0
7f2127164000-7f2127168000 r--p 00000000 00:00 0 [vvar]
7f2127168000-7f212716a000 r-xp 00000000 00:00 0 [vdso]
7fffab3d9000-7fffab3fb000 rw-p 00000000 00:00 0 [stack]
`

for name, tc := range map[string]struct {
reader io.Reader
libName string
expPath string
expErr error
}{
"empty": {},
"nonexistent": {
reader: strings.NewReader(testMap),
libName: "libmystery",
expErr: errors.New("unable to find"),
},
"dupes": {
reader: strings.NewReader(testMap + `
7f2127030000-7f2127032000 rw-p 00030000 fd:01 44043895 /usr/lib64/libwhoops-2.29.so
7f2127030000-7f2127032000 rw-p 00030000 fd:01 44043895 /usr/lib64/libwhoops-2.28.so
`),
libName: "libwhoops",
expErr: errors.New("multiple paths"),
},
"libc": {
reader: strings.NewReader(testMap),
libName: "libc",
expPath: "/usr/lib64/libc-2.28.so",
},
"libunder_score": {
reader: strings.NewReader(testMap + `
7f2127030000-7f2127032000 rw-p 00030000 fd:01 44043895 /usr/lib64/libkool_wow.so.123
7f2127030000-7f2127032000 rw-p 00030000 fd:01 44043895 /usr/lib64/libkool.so.456
`),
libName: "libkool",
expPath: "/usr/lib64/libkool.so.456",
},
} {
t.Run(name, func(t *testing.T) {
gotPath, gotErr := readMappedLibPath(tc.reader, tc.libName)
test.CmpErr(t, tc.expErr, gotErr)
if tc.expErr != nil {
return
}

if diff := cmp.Diff(tc.expPath, gotPath); diff != "" {
t.Fatalf("unexpected path for %q (-want,+got): %s", tc.libName, diff)
}
})
}
}
Loading
Loading