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-16070 tools: Include BuildInfo field in version output #14645

Merged
merged 1 commit into from
Jun 26, 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
13 changes: 13 additions & 0 deletions src/control/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# pylint: disable=too-many-locals
import os
import socket
import subprocess # nosec
from binascii import b2a_hex
from datetime import datetime, timezone
from os import urandom
Expand Down Expand Up @@ -45,20 +46,32 @@ def gen_build_id():
return '0x' + buildid.decode()


def get_build_info():
"""Attempt to retrieve commit/tag details from the build environment."""
try:
cmd = subprocess.run(['git', 'describe', '--tags', '--dirty', '--always'],
stdout=subprocess.PIPE, check=True) # nosec
except (subprocess.CalledProcessError, FileNotFoundError):
return ''
return cmd.stdout.decode().strip()


def go_ldflags(benv):
"Create the ldflags option for the Go build."

build_host = ''
if not is_release_build(benv):
build_host = socket.getfqdn()
build_time = datetime.now(timezone.utc).astimezone().isoformat()
build_info = get_build_info()
Import('daos_version', 'conf_dir')
path = 'github.com/daos-stack/daos/src/control/build'
return ' '.join([f'-X {path}.DaosVersion={daos_version}',
f'-X {path}.ConfigDir={conf_dir}',
f'-X {path}.BuildHost={build_host}',
# NB: dynamic values should be enclosed in $(...$)
# to avoid unnecessary rebuilds
f'-X $({path}.BuildInfo={build_info}$)',
f'-X $({path}.BuildTime={build_time}$)',
f'-B $({gen_build_id()}$)'])

Expand Down
34 changes: 22 additions & 12 deletions src/control/build/string.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2023 Intel Corporation.
// (C) Copyright 2023-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand Down Expand Up @@ -36,7 +36,24 @@ func revString(version string) string {
// String returns a string containing the name, version, and for non-release builds,
// the revision of the binary.
func String(name string) string {
return fmt.Sprintf("%s version %s", name, revString(DaosVersion))
return VersionString(name, revString(DaosVersion))
}

// VersionString returns a string concatenation of the supplied name and version.
func VersionString(name, version string) string {
return fmt.Sprintf("%s version %s", name, version)
}

// Info contains a structured representation of the binary build info.
type Info struct {
Name string `json:"name"`
Version string `json:"version"`
Revision string `json:"revision,omitempty"`
Dirty bool `json:"dirty,omitempty"`
Release bool `json:"release,omitempty"`
BuildHost string `json:"build_host,omitempty"`
BuildTime *time.Time `json:"build_time,omitempty"`
BuildInfo string `json:"build_info,omitempty"`
}

// MarshalJSON returns a JSON string containing a structured representation of
Expand All @@ -45,21 +62,14 @@ func MarshalJSON(name string) ([]byte, error) {
// Not a fatal error if the build time can't be parsed.
buildTime, _ := time.Parse(time.RFC3339, BuildTime)

return json.Marshal(&struct {
Name string `json:"name"`
Version string `json:"version"`
Revision string `json:"revision,omitempty"`
Dirty bool `json:"dirty,omitempty"`
Release bool `json:"release,omitempty"`
BuildHost string `json:"build_host,omitempty"`
BuildTime time.Time `json:"build_time,omitempty"`
}{
return json.Marshal(&Info{
Name: name,
Version: DaosVersion,
Revision: Revision,
Dirty: DirtyBuild,
Release: ReleaseBuild,
BuildHost: BuildHost,
BuildTime: buildTime,
BuildTime: &buildTime,
BuildInfo: BuildInfo,
})
}
4 changes: 3 additions & 1 deletion src/control/build/variables.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2020-2023 Intel Corporation.
// (C) Copyright 2020-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand All @@ -18,6 +18,8 @@ var (
BuildTime = ""
// BuildHost should be set via linker flag using the value of BUILD_HOST.
BuildHost = ""
// BuildInfo should be set via linker flag using the value of BUILD_INFO.
BuildInfo = ""
// ControlPlaneName defines a consistent name for the control plane server.
ControlPlaneName = "DAOS Control Server"
// DataPlaneName defines a consistent name for the engine.
Expand Down
46 changes: 35 additions & 11 deletions src/control/cmd/daos/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2021-2023 Intel Corporation.
// (C) Copyright 2021-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand All @@ -24,16 +24,17 @@ import (
)

type cliOptions struct {
Debug bool `long:"debug" description:"enable debug output"`
Verbose bool `long:"verbose" description:"enable verbose output (when applicable)"`
JSON bool `long:"json" short:"j" description:"enable JSON output"`
Container containerCmd `command:"container" alias:"cont" description:"perform tasks related to DAOS containers"`
Pool poolCmd `command:"pool" description:"perform tasks related to DAOS pools"`
Filesystem fsCmd `command:"filesystem" alias:"fs" description:"POSIX filesystem operations"`
Object objectCmd `command:"object" alias:"obj" description:"DAOS object operations"`
System systemCmd `command:"system" alias:"sys" description:"DAOS system operations"`
Version versionCmd `command:"version" description:"print daos version"`
ManPage cmdutil.ManCmd `command:"manpage" hidden:"true"`
Debug bool `long:"debug" description:"enable debug output"`
Verbose bool `long:"verbose" description:"enable verbose output (when applicable)"`
JSON bool `long:"json" short:"j" description:"enable JSON output"`
Container containerCmd `command:"container" alias:"cont" description:"perform tasks related to DAOS containers"`
Pool poolCmd `command:"pool" description:"perform tasks related to DAOS pools"`
Filesystem fsCmd `command:"filesystem" alias:"fs" description:"POSIX filesystem operations"`
Object objectCmd `command:"object" alias:"obj" description:"DAOS object operations"`
System systemCmd `command:"system" alias:"sys" description:"DAOS system operations"`
Version versionCmd `command:"version" description:"print daos version"`
ServerVersion serverVersionCmd `command:"server-version" description:"Print server version"`
ManPage cmdutil.ManCmd `command:"manpage" hidden:"true"`
}

type versionCmd struct {
Expand All @@ -54,6 +55,29 @@ func (cmd *versionCmd) Execute(_ []string) error {
return nil
}

type serverVersionCmd struct {
daosCmd
cmdutil.JSONOutputCmd
}

func (cmd *serverVersionCmd) Execute(_ []string) error {
buildInfo, err := srvBuildInfo()
if err != nil {
return errors.Wrap(err, "failed to get server build info")
}

if cmd.JSONOutputEnabled() {
buf, err := json.Marshal(buildInfo)
if err != nil {
return err
}
return cmd.OutputJSON(json.RawMessage(buf), nil)
}

_, err = fmt.Println(build.VersionString(build.ControlPlaneName, buildInfo.Version))
return err
}

func exitWithError(log logging.Logger, err error) {
cmdName := path.Base(os.Args[0])
log.Errorf("%s: %v", cmdName, err)
Expand Down
22 changes: 21 additions & 1 deletion src/control/cmd/daos/util.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2021-2023 Intel Corporation.
// (C) Copyright 2021-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand All @@ -17,6 +17,7 @@ import (
"github.com/google/uuid"
"github.com/pkg/errors"

"github.com/daos-stack/daos/src/control/build"
"github.com/daos-stack/daos/src/control/common/cmdutil"
"github.com/daos-stack/daos/src/control/lib/daos"
"github.com/daos-stack/daos/src/control/logging"
Expand Down Expand Up @@ -62,6 +63,25 @@ func apiVersion() string {
)
}

func srvBuildInfo() (*build.Info, error) {
var major uint32
var minor uint32
var patch uint32
var tagPtr *C.char

rc := C.dc_mgmt_srv_version((*C.uint)(&major), (*C.uint)(&minor), (*C.uint)(&patch), &tagPtr)
if err := daosError(rc); err != nil {
return nil, err
}
tagStr := C.GoString(tagPtr)

return &build.Info{
Name: build.ControlPlaneName,
Version: (&build.Version{Major: int(major), Minor: int(minor), Patch: int(patch)}).String(),
BuildInfo: tagStr,
}, nil
}

func daosError(rc C.int) error {
if rc == 0 {
return nil
Expand Down
24 changes: 17 additions & 7 deletions src/control/cmd/daos_agent/attachinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package main

import (
"context"
"fmt"
"os"

Expand All @@ -17,11 +18,24 @@ import (
"github.com/daos-stack/daos/src/control/lib/txtfmt"
)

type dumpAttachInfoCmd struct {
type attachInfoCmd struct {
configCmd
ctlInvokerCmd
cmdutil.LogCmd
cmdutil.JSONOutputCmd
}

func (cmd *attachInfoCmd) getAttachInfo(ctx context.Context) (*control.GetAttachInfoResp, error) {
req := &control.GetAttachInfoReq{
AllRanks: true,
}
req.SetSystem(cmd.cfg.SystemName)
resp, err := control.GetAttachInfo(ctx, cmd.ctlInvoker, req)
return resp, errors.Wrap(err, "GetAttachInfo failed")
}

type dumpAttachInfoCmd struct {
attachInfoCmd
Output string `short:"o" long:"output" default:"stdout" description:"Dump output to this location"`
}

Expand All @@ -37,13 +51,9 @@ func (cmd *dumpAttachInfoCmd) Execute(_ []string) error {
}

ctx := cmd.MustLogCtx()
req := &control.GetAttachInfoReq{
AllRanks: true,
}
req.SetSystem(cmd.cfg.SystemName)
resp, err := control.GetAttachInfo(ctx, cmd.ctlInvoker, req)
resp, err := cmd.getAttachInfo(ctx)
if err != nil {
return errors.Wrap(err, "GetAttachInfo failed")
return err
}

if cmd.JSONOutputEnabled() {
Expand Down
57 changes: 42 additions & 15 deletions src/control/cmd/daos_agent/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2018-2023 Intel Corporation.
// (C) Copyright 2018-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand All @@ -26,20 +26,21 @@ import (
)

type cliOptions struct {
AllowProxy bool `long:"allow-proxy" description:"Allow proxy configuration via environment"`
Debug bool `short:"d" long:"debug" description:"Enable debug output"`
JSON bool `short:"j" long:"json" description:"Enable JSON output"`
JSONLogs bool `short:"J" long:"json-logging" description:"Enable JSON-formatted log output"`
ConfigPath string `short:"o" long:"config-path" description:"Path to agent configuration file"`
Insecure bool `short:"i" long:"insecure" description:"have agent attempt to connect without certificates"`
RuntimeDir string `short:"s" long:"runtime_dir" description:"Path to agent communications socket"`
LogFile string `short:"l" long:"logfile" description:"Full path and filename for daos agent log file"`
Start startCmd `command:"start" description:"Start daos_agent daemon (default behavior)"`
Version versionCmd `command:"version" description:"Print daos_agent version"`
DumpInfo dumpAttachInfoCmd `command:"dump-attachinfo" description:"Dump system attachinfo"`
DumpTopo hwprov.DumpTopologyCmd `command:"dump-topology" description:"Dump system topology"`
NetScan netScanCmd `command:"net-scan" description:"Perform local network fabric scan"`
Support supportCmd `command:"support" description:"Perform debug tasks to help support team"`
AllowProxy bool `long:"allow-proxy" description:"Allow proxy configuration via environment"`
Debug bool `short:"d" long:"debug" description:"Enable debug output"`
JSON bool `short:"j" long:"json" description:"Enable JSON output"`
JSONLogs bool `short:"J" long:"json-logging" description:"Enable JSON-formatted log output"`
ConfigPath string `short:"o" long:"config-path" description:"Path to agent configuration file"`
Insecure bool `short:"i" long:"insecure" description:"have agent attempt to connect without certificates"`
RuntimeDir string `short:"s" long:"runtime_dir" description:"Path to agent communications socket"`
LogFile string `short:"l" long:"logfile" description:"Full path and filename for daos agent log file"`
Start startCmd `command:"start" description:"Start daos_agent daemon (default behavior)"`
Version versionCmd `command:"version" description:"Print daos_agent version"`
ServerVersion serverVersionCmd `command:"server-version" description:"Print daos_server version"`
DumpInfo dumpAttachInfoCmd `command:"dump-attachinfo" description:"Dump system attachinfo"`
DumpTopo hwprov.DumpTopologyCmd `command:"dump-topology" description:"Dump system topology"`
NetScan netScanCmd `command:"net-scan" description:"Perform local network fabric scan"`
Support supportCmd `command:"support" description:"Perform debug tasks to help support team"`
}

type (
Expand Down Expand Up @@ -91,6 +92,32 @@ func (cmd *versionCmd) Execute(_ []string) error {
return err
}

type serverVersionCmd struct {
attachInfoCmd
}

func (cmd *serverVersionCmd) Execute(_ []string) error {
resp, err := cmd.getAttachInfo(cmd.MustLogCtx())
if err != nil {
return err
}

if cmd.JSONOutputEnabled() {
buf, err := json.Marshal(&build.Info{
Name: build.ControlPlaneName,
Version: resp.BuildInfo.VersionString(),
BuildInfo: resp.BuildInfo.Tag,
})
if err != nil {
return err
}
return cmd.OutputJSON(json.RawMessage(buf), nil)
}

_, err = fmt.Println(build.VersionString(build.ControlPlaneName, resp.BuildInfo.VersionString()))
return err
}

func exitWithError(log logging.Logger, err error) {
log.Errorf("%s: %v", path.Base(os.Args[0]), err)
os.Exit(1)
Expand Down
10 changes: 4 additions & 6 deletions src/control/cmd/daos_agent/mgmt_rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
"google.golang.org/protobuf/proto"
Expand Down Expand Up @@ -218,11 +217,10 @@ func TestAgent_mgmtModule_getAttachInfo(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(tc.expResp, resp, cmpopts.IgnoreUnexported(
mgmtpb.GetAttachInfoResp{},
mgmtpb.GetAttachInfoResp_RankUri{},
mgmtpb.ClientNetHint{},
)); diff != "" {
cmpOpts := cmp.Options{
protocmp.Transform(),
}
if diff := cmp.Diff(tc.expResp, resp, cmpOpts...); diff != "" {
t.Fatalf("want-, got+:\n%s", diff)
}
})
Expand Down
4 changes: 3 additions & 1 deletion src/control/cmd/dmg/command_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// (C) Copyright 2019-2022 Intel Corporation.
// (C) Copyright 2019-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
Expand Down Expand Up @@ -173,6 +173,8 @@ func (bci *bridgeConnInvoker) InvokeUnaryRPC(ctx context.Context, uReq control.U
resp = control.MockMSResponse("", nil, &mgmtpb.DaosResp{})
case *control.SystemGetPropReq:
resp = control.MockMSResponse("", nil, &mgmtpb.SystemGetPropResp{})
case *control.GetAttachInfoReq:
resp = control.MockMSResponse("", nil, &mgmtpb.GetAttachInfoResp{})
case *control.NetworkScanReq:
resp = &control.UnaryResponse{
Responses: []*control.HostResponse{
Expand Down
Loading
Loading