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-10028 control: Move core types into daos package #14174

Merged
merged 23 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d73d0dd
DAOS-10028 control: Move core types into daos package
mjmac Apr 12, 2024
33f1d61
Address review feedback
mjmac Apr 17, 2024
44e9b9c
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 18, 2024
8ef0b8d
Converge on svc_ldr for JSON field name
mjmac Apr 18, 2024
f8637bb
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 20, 2024
7774a48
fix a few more broken tests
mjmac Apr 20, 2024
ff065b7
Update expected output in list_verbose.py tests
mjmac Apr 23, 2024
837cc09
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 23, 2024
d734c1e
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 23, 2024
adb2099
Fix wonky clang-format changes
mjmac Apr 24, 2024
0088935
Fix dict key (why not just use the JSON keys??)
mjmac Apr 24, 2024
5069a56
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 29, 2024
e20fd59
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 29, 2024
9fbf277
Adjust expected output in list_verbose.py
mjmac Apr 29, 2024
a0b54f0
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac Apr 30, 2024
19c8644
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac May 2, 2024
f6d3e7b
Update control/dmg_pool_query_test.py
mjmac May 2, 2024
0b63c75
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac May 4, 2024
140c2b2
Fix pool query test
mjmac May 4, 2024
b950a2c
Rargh. Fix a Go unit test
mjmac May 6, 2024
18388a5
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac May 6, 2024
fcd9fad
forgot to update the tier_name field
mjmac May 6, 2024
03c76ec
Merge branch 'master' into mjmac/DAOS-10028-pool
mjmac May 6, 2024
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
107 changes: 45 additions & 62 deletions src/control/cmd/daos/pool.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 @@ -15,11 +15,9 @@ import (
"github.com/google/uuid"
"github.com/pkg/errors"

"github.com/daos-stack/daos/src/control/cmd/dmg/pretty"
"github.com/daos-stack/daos/src/control/cmd/daos/pretty"
"github.com/daos-stack/daos/src/control/common"
"github.com/daos-stack/daos/src/control/common/proto/convert"
mgmtpb "github.com/daos-stack/daos/src/control/common/proto/mgmt"
"github.com/daos-stack/daos/src/control/lib/control"
"github.com/daos-stack/daos/src/control/lib/daos"
"github.com/daos-stack/daos/src/control/lib/ranklist"
"github.com/daos-stack/daos/src/control/lib/ui"
)
Expand Down Expand Up @@ -198,74 +196,63 @@ type poolQueryCmd struct {
ShowDisabledRanks bool `short:"b" long:"show-disabled" description:"Show engine unique identifiers (ranks) which are disabled"`
}

func convertPoolSpaceInfo(in *C.struct_daos_pool_space, mt C.uint) *mgmtpb.StorageUsageStats {
func convertPoolSpaceInfo(in *C.struct_daos_pool_space, mt C.uint) *daos.StorageUsageStats {
if in == nil {
return nil
}

return &mgmtpb.StorageUsageStats{
return &daos.StorageUsageStats{
Total: uint64(in.ps_space.s_total[mt]),
Free: uint64(in.ps_space.s_free[mt]),
Min: uint64(in.ps_free_min[mt]),
Max: uint64(in.ps_free_max[mt]),
Mean: uint64(in.ps_free_mean[mt]),
MediaType: mgmtpb.StorageMediaType(mt),
MediaType: daos.StorageMediaType(mt),
}
}

func convertPoolRebuildStatus(in *C.struct_daos_rebuild_status) *mgmtpb.PoolRebuildStatus {
func convertPoolRebuildStatus(in *C.struct_daos_rebuild_status) *daos.PoolRebuildStatus {
if in == nil {
return nil
}

out := &mgmtpb.PoolRebuildStatus{
out := &daos.PoolRebuildStatus{
Status: int32(in.rs_errno),
}
if out.Status == 0 {
out.Objects = uint64(in.rs_obj_nr)
out.Records = uint64(in.rs_rec_nr)
switch {
case in.rs_version == 0:
out.State = mgmtpb.PoolRebuildStatus_IDLE
out.State = daos.PoolRebuildStateIdle
case C.get_rebuild_state(in) == C.DRS_COMPLETED:
out.State = mgmtpb.PoolRebuildStatus_DONE
out.State = daos.PoolRebuildStateDone
default:
out.State = mgmtpb.PoolRebuildStatus_BUSY
out.State = daos.PoolRebuildStateBusy
}
}

return out
}

// This is not great... But it allows us to leverage the existing
// pretty printer that dmg uses for this info. Better to find some
// way to unify all of this and remove redundancy/manual conversion.
//
// We're basically doing the same thing as ds_mgmt_drpc_pool_query()
// to stuff the info into a protobuf message and then using the
// automatic conversion from proto to control. Kind of ugly but
// gets the job done. We could potentially create some function
// that's shared between this code and the drpc handlers to deal
// with stuffing the protobuf message but it's probably overkill.
func convertPoolInfo(pinfo *C.daos_pool_info_t) (*control.PoolQueryResp, error) {
pqp := new(mgmtpb.PoolQueryResp)

pqp.Uuid = uuid.Must(uuidFromC(pinfo.pi_uuid)).String()
pqp.TotalTargets = uint32(pinfo.pi_ntargets)
pqp.DisabledTargets = uint32(pinfo.pi_ndisabled)
pqp.ActiveTargets = uint32(pinfo.pi_space.ps_ntargets)
pqp.TotalEngines = uint32(pinfo.pi_nnodes)
pqp.Leader = uint32(pinfo.pi_leader)
pqp.Version = uint32(pinfo.pi_map_ver)

pqp.TierStats = []*mgmtpb.StorageUsageStats{
func convertPoolInfo(pinfo *C.daos_pool_info_t) (*daos.PoolInfo, error) {
poolInfo := new(daos.PoolInfo)

poolInfo.UUID = uuid.Must(uuidFromC(pinfo.pi_uuid))
poolInfo.TotalTargets = uint32(pinfo.pi_ntargets)
poolInfo.DisabledTargets = uint32(pinfo.pi_ndisabled)
poolInfo.ActiveTargets = uint32(pinfo.pi_space.ps_ntargets)
poolInfo.TotalEngines = uint32(pinfo.pi_nnodes)
poolInfo.ServiceLeader = uint32(pinfo.pi_leader)
poolInfo.Version = uint32(pinfo.pi_map_ver)

poolInfo.TierStats = []*daos.StorageUsageStats{
convertPoolSpaceInfo(&pinfo.pi_space, C.DAOS_MEDIA_SCM),
convertPoolSpaceInfo(&pinfo.pi_space, C.DAOS_MEDIA_NVME),
}
pqp.Rebuild = convertPoolRebuildStatus(&pinfo.pi_rebuild_st)
poolInfo.Rebuild = convertPoolRebuildStatus(&pinfo.pi_rebuild_st)

pqr := new(control.PoolQueryResp)
return pqr, convert.Types(pqp, pqr)
return poolInfo, nil
}

const (
Expand Down Expand Up @@ -308,46 +295,40 @@ func (cmd *poolQueryCmd) Execute(_ []string) error {
}
defer cleanup()

pinfo := C.daos_pool_info_t{
cPoolInfo := C.daos_pool_info_t{
pi_bits: dpiQueryAll,
}
if cmd.ShowDisabledRanks {
pinfo.pi_bits &= C.uint64_t(^(uint64(C.DPI_ENGINES_ENABLED)))
cPoolInfo.pi_bits &= C.uint64_t(^(uint64(C.DPI_ENGINES_ENABLED)))
}

rc := C.daos_pool_query(cmd.cPoolHandle, rlPtr, &pinfo, nil, nil)
rc := C.daos_pool_query(cmd.cPoolHandle, rlPtr, &cPoolInfo, nil, nil)
defer C.d_rank_list_free(rl)
if err := daosError(rc); err != nil {
return errors.Wrapf(err,
"failed to query pool %s", cmd.poolUUID)
}

pqr, err := convertPoolInfo(&pinfo)
poolInfo, err := convertPoolInfo(&cPoolInfo)
if err != nil {
return err
}

if rlPtr != nil {
if cmd.ShowEnabledRanks {
pqr.EnabledRanks = ranklist.MustCreateRankSet(generateRankSet(rl))
poolInfo.EnabledRanks = ranklist.MustCreateRankSet(generateRankSet(rl))
}
if cmd.ShowDisabledRanks {
pqr.DisabledRanks = ranklist.MustCreateRankSet(generateRankSet(rl))
poolInfo.DisabledRanks = ranklist.MustCreateRankSet(generateRankSet(rl))
}
}

// Update the Pool Query State based on response
err = pqr.UpdateState()
if err != nil {
return err
}

if cmd.JSONOutputEnabled() {
return cmd.OutputJSON(pqr, nil)
return cmd.OutputJSON(poolInfo, nil)
}

var bld strings.Builder
if err := pretty.PrintPoolQueryResponse(pqr, &bld); err != nil {
if err := pretty.PrintPoolInfo(poolInfo, &bld); err != nil {
return err
}

Expand All @@ -364,11 +345,11 @@ type poolQueryTargetsCmd struct {
}

// For using the pretty printer that dmg uses for this target info.
func convertPoolTargetInfo(ptinfo *C.daos_target_info_t) (*control.PoolQueryTargetInfo, error) {
pqti := new(control.PoolQueryTargetInfo)
pqti.Type = control.PoolQueryTargetType(ptinfo.ta_type)
pqti.State = control.PoolQueryTargetState(ptinfo.ta_state)
pqti.Space = []*control.StorageTargetUsage{
func convertPoolTargetInfo(ptinfo *C.daos_target_info_t) (*daos.PoolQueryTargetInfo, error) {
pqti := new(daos.PoolQueryTargetInfo)
pqti.Type = daos.PoolQueryTargetType(ptinfo.ta_type)
pqti.State = daos.PoolQueryTargetState(ptinfo.ta_state)
pqti.Space = []*daos.StorageUsageStats{
{
Total: uint64(ptinfo.ta_space.s_total[C.DAOS_MEDIA_SCM]),
Free: uint64(ptinfo.ta_space.s_free[C.DAOS_MEDIA_SCM]),
Expand Down Expand Up @@ -396,10 +377,10 @@ func (cmd *poolQueryTargetsCmd) Execute(_ []string) error {
return errors.WithMessage(err, "parsing target list")
}

infoResp := new(control.PoolQueryTargetResp)
ptInfo := new(C.daos_target_info_t)
var rc C.int

infos := make([]*daos.PoolQueryTargetInfo, 0, len(idxList))
for tgt := 0; tgt < len(idxList); tgt++ {
rc = C.daos_pool_query_target(cmd.cPoolHandle, C.uint32_t(idxList[tgt]), C.uint32_t(cmd.Rank), ptInfo, nil)
if err := daosError(rc); err != nil {
Expand All @@ -408,19 +389,21 @@ func (cmd *poolQueryTargetsCmd) Execute(_ []string) error {
}

tgtInfo, err := convertPoolTargetInfo(ptInfo)
infoResp.Infos = append(infoResp.Infos, tgtInfo)
if err != nil {
return err
}
infos = append(infos, tgtInfo)
}

if cmd.JSONOutputEnabled() {
return cmd.OutputJSON(infoResp, nil)
return cmd.OutputJSON(infos, nil)
}

var bld strings.Builder
if err := pretty.PrintPoolQueryTargetResponse(infoResp, &bld); err != nil {
return err
for _, info := range infos {
if err := pretty.PrintPoolQueryTargetInfo(info, &bld); err != nil {
return err
}
}

cmd.Info(bld.String())
Expand Down
97 changes: 97 additions & 0 deletions src/control/cmd/daos/pretty/pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//
// (C) Copyright 2020-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//

package pretty

import (
"fmt"
"io"

"github.com/dustin/go-humanize"
"github.com/pkg/errors"

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

const msgNoPools = "No pools in system"

func getTierNameText(tierIdx int) string {
switch tierIdx {
case int(daos.StorageMediaTypeScm):
return fmt.Sprintf("- Storage tier %d (SCM):", tierIdx)
case int(daos.StorageMediaTypeNvme):
return fmt.Sprintf("- Storage tier %d (NVMe):", tierIdx)
default:
return fmt.Sprintf("- Storage tier %d (unknown):", tierIdx)
}
}

// PrintPoolInfo generates a human-readable representation of the supplied
// PoolQueryResp struct and writes it to the supplied io.Writer.
func PrintPoolInfo(pi *daos.PoolInfo, out io.Writer) error {
if pi == nil {
return errors.Errorf("nil %T", pi)
}
w := txtfmt.NewErrWriter(out)

// Maintain output compatibility with the `daos pool query` output.
fmt.Fprintf(w, "Pool %s, ntarget=%d, disabled=%d, leader=%d, version=%d, state=%s\n",
pi.UUID, pi.TotalTargets, pi.DisabledTargets, pi.ServiceLeader, pi.Version, pi.State)

if pi.PoolLayoutVer != pi.UpgradeLayoutVer {
fmt.Fprintf(w, "Pool layout out of date (%d < %d) -- see `dmg pool upgrade` for details.\n",
pi.PoolLayoutVer, pi.UpgradeLayoutVer)
}
fmt.Fprintln(w, "Pool space info:")
if pi.EnabledRanks != nil {
fmt.Fprintf(w, "- Enabled ranks: %s\n", pi.EnabledRanks)
}
if pi.DisabledRanks != nil {
fmt.Fprintf(w, "- Disabled ranks: %s\n", pi.DisabledRanks)
}
fmt.Fprintf(w, "- Target(VOS) count:%d\n", pi.ActiveTargets)
if pi.TierStats != nil {
for tierIdx, tierStats := range pi.TierStats {
fmt.Fprintln(w, getTierNameText(tierIdx))
fmt.Fprintf(w, " Total size: %s\n", humanize.Bytes(tierStats.Total))
fmt.Fprintf(w, " Free: %s, min:%s, max:%s, mean:%s\n",
humanize.Bytes(tierStats.Free), humanize.Bytes(tierStats.Min),
humanize.Bytes(tierStats.Max), humanize.Bytes(tierStats.Mean))
}
}
if pi.Rebuild != nil {
if pi.Rebuild.Status == 0 {
fmt.Fprintf(w, "Rebuild %s, %d objs, %d recs\n",
pi.Rebuild.State, pi.Rebuild.Objects, pi.Rebuild.Records)
} else {
fmt.Fprintf(w, "Rebuild failed, status=%d\n", pi.Rebuild.Status)
}
}

return w.Err
}

// PrintPoolQueryTargetInfo generates a human-readable representation of the supplied
// PoolQueryTargetResp struct and writes it to the supplied io.Writer.
func PrintPoolQueryTargetInfo(pqti *daos.PoolQueryTargetInfo, out io.Writer) error {
if pqti == nil {
return errors.Errorf("nil %T", pqti)
}
w := txtfmt.NewErrWriter(out)

// Maintain output compatibility with the `daos pool query-targets` output.
fmt.Fprintf(w, "Target: type %s, state %s\n", pqti.Type, pqti.State)
if pqti.Space != nil {
for tierIdx, tierUsage := range pqti.Space {
fmt.Fprintln(w, getTierNameText(tierIdx))
fmt.Fprintf(w, " Total size: %s\n", humanize.Bytes(tierUsage.Total))
fmt.Fprintf(w, " Free: %s\n", humanize.Bytes(tierUsage.Free))
}
}

return w.Err
}
Loading
Loading