From 33f1d611d0429acec4475a1b4347bb84686bf870 Mon Sep 17 00:00:00 2001 From: Michael MacDonald Date: Wed, 17 Apr 2024 18:40:43 +0000 Subject: [PATCH] Address review feedback Move PoolQueryTarget and related types into lib/daos. Features: pool Required-githooks: true Change-Id: Ibb90c44d681402b699e023cc78adb4b7f21b0910 Signed-off-by: Michael MacDonald --- src/control/cmd/daos/pool.go | 106 +++----- src/control/cmd/daos/pretty/pool.go | 23 +- src/control/cmd/daos/pretty/pool_test.go | 176 ++++++++++++ src/control/cmd/dmg/pretty/pool.go | 17 +- src/control/cmd/dmg/pretty/pool_test.go | 250 +++--------------- src/control/lib/control/pool.go | 70 +---- src/control/lib/daos/pool.go | 153 ++++++----- src/control/system/raft/raft_recovery_test.go | 11 +- 8 files changed, 387 insertions(+), 419 deletions(-) diff --git a/src/control/cmd/daos/pool.go b/src/control/cmd/daos/pool.go index b2ccacbe49c..30e697f921b 100644 --- a/src/control/cmd/daos/pool.go +++ b/src/control/cmd/daos/pool.go @@ -1,5 +1,5 @@ // -// (C) Copyright 2021-2023 Intel Corporation. +// (C) Copyright 2021-2024 Intel Corporation. // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -16,11 +16,8 @@ import ( "github.com/pkg/errors" "github.com/daos-stack/daos/src/control/build" - "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" @@ -201,27 +198,27 @@ 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 { @@ -229,46 +226,35 @@ func convertPoolRebuildStatus(in *C.struct_daos_rebuild_status) *mgmtpb.PoolRebu 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.Leader = 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 ( @@ -311,46 +297,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 } @@ -367,11 +347,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 = []*daos.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]), @@ -399,10 +379,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 { @@ -411,19 +391,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()) diff --git a/src/control/cmd/daos/pretty/pool.go b/src/control/cmd/daos/pretty/pool.go index 26afcc79d04..b8261a13626 100644 --- a/src/control/cmd/daos/pretty/pool.go +++ b/src/control/cmd/daos/pretty/pool.go @@ -1,5 +1,5 @@ // -// (C) Copyright 2020-2023 Intel Corporation. +// (C) Copyright 2020-2024 Intel Corporation. // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -74,3 +74,24 @@ func PrintPoolInfo(pi *daos.PoolInfo, out io.Writer) error { 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 +} diff --git a/src/control/cmd/daos/pretty/pool_test.go b/src/control/cmd/daos/pretty/pool_test.go index 261a616a953..f80e66f0f12 100644 --- a/src/control/cmd/daos/pretty/pool_test.go +++ b/src/control/cmd/daos/pretty/pool_test.go @@ -7,6 +7,7 @@ package pretty import ( + "errors" "fmt" "strings" "testing" @@ -259,3 +260,178 @@ Rebuild failed, status=2 }) } } + +func TestPretty_PrintPoolQueryTarget(t *testing.T) { + for name, tc := range map[string]struct { + pqti *daos.PoolQueryTargetInfo + expErr error + expPrintStr string + }{ + "nil info": { + expErr: errors.New("nil"), + }, + "valid: single target (unknown, down_out)": { + pqti: &daos.PoolQueryTargetInfo{ + Type: 0, + State: daos.PoolTargetStateDownOut, + Space: []*daos.StorageUsageStats{ + { + Total: 6000000000, + Free: 5000000000, + }, + { + Total: 100000000000, + Free: 90000000000, + }, + }, + }, + expPrintStr: ` +Target: type unknown, state down_out +- Storage tier 0 (SCM): + Total size: 6.0 GB + Free: 5.0 GB +- Storage tier 1 (NVMe): + Total size: 100 GB + Free: 90 GB +`, + }, + "valid: single target (unknown, down)": { + pqti: &daos.PoolQueryTargetInfo{ + Type: 0, + State: daos.PoolTargetStateDown, + Space: []*daos.StorageUsageStats{ + { + Total: 6000000000, + Free: 5000000000, + }, + { + Total: 100000000000, + Free: 90000000000, + }, + }, + }, + expPrintStr: ` +Target: type unknown, state down +- Storage tier 0 (SCM): + Total size: 6.0 GB + Free: 5.0 GB +- Storage tier 1 (NVMe): + Total size: 100 GB + Free: 90 GB +`, + }, + "valid: single target (unknown, up)": { + pqti: &daos.PoolQueryTargetInfo{ + Type: 0, + State: daos.PoolTargetStateUp, + Space: []*daos.StorageUsageStats{ + { + Total: 6000000000, + Free: 5000000000, + }, + { + Total: 100000000000, + Free: 90000000000, + }, + }, + }, + expPrintStr: ` +Target: type unknown, state up +- Storage tier 0 (SCM): + Total size: 6.0 GB + Free: 5.0 GB +- Storage tier 1 (NVMe): + Total size: 100 GB + Free: 90 GB +`, + }, + "valid: single target (unknown, up_in)": { + pqti: &daos.PoolQueryTargetInfo{ + Type: 0, + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ + { + Total: 6000000000, + Free: 5000000000, + }, + { + Total: 100000000000, + Free: 90000000000, + }, + }, + }, + expPrintStr: ` +Target: type unknown, state up_in +- Storage tier 0 (SCM): + Total size: 6.0 GB + Free: 5.0 GB +- Storage tier 1 (NVMe): + Total size: 100 GB + Free: 90 GB +`, + }, + "valid: single target (unknown, new)": { + pqti: &daos.PoolQueryTargetInfo{ + Type: 0, + State: daos.PoolTargetStateNew, + Space: []*daos.StorageUsageStats{ + { + Total: 6000000000, + Free: 5000000000, + }, + { + Total: 100000000000, + Free: 90000000000, + }, + }, + }, + expPrintStr: ` +Target: type unknown, state new +- Storage tier 0 (SCM): + Total size: 6.0 GB + Free: 5.0 GB +- Storage tier 1 (NVMe): + Total size: 100 GB + Free: 90 GB +`, + }, + "valid: single target (unknown, drain)": { + pqti: &daos.PoolQueryTargetInfo{ + Type: 0, + State: daos.PoolTargetStateDrain, + Space: []*daos.StorageUsageStats{ + { + Total: 6000000000, + Free: 5000000000, + }, + { + Total: 100000000000, + Free: 90000000000, + }, + }, + }, + expPrintStr: ` +Target: type unknown, state drain +- Storage tier 0 (SCM): + Total size: 6.0 GB + Free: 5.0 GB +- Storage tier 1 (NVMe): + Total size: 100 GB + Free: 90 GB +`, + }, + } { + t.Run(name, func(t *testing.T) { + var bld strings.Builder + gotErr := PrintPoolQueryTargetInfo(tc.pqti, &bld) + test.CmpErr(t, tc.expErr, gotErr) + if tc.expErr != nil { + return + } + + if diff := cmp.Diff(strings.TrimLeft(tc.expPrintStr, "\n"), bld.String()); diff != "" { + t.Fatalf("unexpected format string (-want, +got):\n%s\n", diff) + } + }) + } +} diff --git a/src/control/cmd/dmg/pretty/pool.go b/src/control/cmd/dmg/pretty/pool.go index 42a5781451f..f2bff92a7d8 100644 --- a/src/control/cmd/dmg/pretty/pool.go +++ b/src/control/cmd/dmg/pretty/pool.go @@ -45,21 +45,14 @@ func PrintPoolQueryTargetResponse(pqtr *control.PoolQueryTargetResp, out io.Writ if pqtr == nil { return errors.Errorf("nil %T", pqtr) } - w := txtfmt.NewErrWriter(out) - - // Maintain output compatibility with the `daos pool query-targets` output. - for infosIdx := range pqtr.Infos { - fmt.Fprintf(w, "Target: type %s, state %s\n", pqtr.Infos[infosIdx].Type, pqtr.Infos[infosIdx].State) - if pqtr.Infos[infosIdx].Space != nil { - for tierIdx, tierUsage := range pqtr.Infos[infosIdx].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)) - } + + for _, info := range pqtr.Infos { + if err := pretty.PrintPoolQueryTargetInfo(info, out); err != nil { + return err } } - return w.Err + return nil } // PrintTierRatio generates a human-readable representation of the supplied diff --git a/src/control/cmd/dmg/pretty/pool_test.go b/src/control/cmd/dmg/pretty/pool_test.go index a5654032438..e61870cef1c 100644 --- a/src/control/cmd/dmg/pretty/pool_test.go +++ b/src/control/cmd/dmg/pretty/pool_test.go @@ -37,194 +37,14 @@ func TestPretty_PrintPoolQueryTargetResp(t *testing.T) { }, expPrintStr: "\n", }, - "valid: single target (unknown, down_out)": { - pqtr: &control.PoolQueryTargetResp{ - Status: 0, - Infos: []*control.PoolQueryTargetInfo{ - { - Type: 0, - State: control.PoolTargetStateDownOut, - Space: []*daos.StorageTargetUsage{ - { - Total: 6000000000, - Free: 5000000000, - }, - { - Total: 100000000000, - Free: 90000000000, - }, - }, - }, - }, - }, - expPrintStr: ` -Target: type unknown, state down_out -- Storage tier 0 (SCM): - Total size: 6.0 GB - Free: 5.0 GB -- Storage tier 1 (NVMe): - Total size: 100 GB - Free: 90 GB -`, - }, - "valid: single target (unknown, down)": { - pqtr: &control.PoolQueryTargetResp{ - Status: 0, - Infos: []*control.PoolQueryTargetInfo{ - { - Type: 0, - State: control.PoolTargetStateDown, - Space: []*daos.StorageTargetUsage{ - { - Total: 6000000000, - Free: 5000000000, - }, - { - Total: 100000000000, - Free: 90000000000, - }, - }, - }, - }, - }, - expPrintStr: ` -Target: type unknown, state down -- Storage tier 0 (SCM): - Total size: 6.0 GB - Free: 5.0 GB -- Storage tier 1 (NVMe): - Total size: 100 GB - Free: 90 GB -`, - }, - "valid: single target (unknown, up)": { - pqtr: &control.PoolQueryTargetResp{ - Status: 0, - Infos: []*control.PoolQueryTargetInfo{ - { - Type: 0, - State: control.PoolTargetStateUp, - Space: []*daos.StorageTargetUsage{ - { - Total: 6000000000, - Free: 5000000000, - }, - { - Total: 100000000000, - Free: 90000000000, - }, - }, - }, - }, - }, - expPrintStr: ` -Target: type unknown, state up -- Storage tier 0 (SCM): - Total size: 6.0 GB - Free: 5.0 GB -- Storage tier 1 (NVMe): - Total size: 100 GB - Free: 90 GB -`, - }, - "valid: single target (unknown, up_in)": { - pqtr: &control.PoolQueryTargetResp{ - Status: 0, - Infos: []*control.PoolQueryTargetInfo{ - { - Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ - { - Total: 6000000000, - Free: 5000000000, - }, - { - Total: 100000000000, - Free: 90000000000, - }, - }, - }, - }, - }, - expPrintStr: ` -Target: type unknown, state up_in -- Storage tier 0 (SCM): - Total size: 6.0 GB - Free: 5.0 GB -- Storage tier 1 (NVMe): - Total size: 100 GB - Free: 90 GB -`, - }, - "valid: single target (unknown, new)": { - pqtr: &control.PoolQueryTargetResp{ - Status: 0, - Infos: []*control.PoolQueryTargetInfo{ - { - Type: 0, - State: control.PoolTargetStateNew, - Space: []*daos.StorageTargetUsage{ - { - Total: 6000000000, - Free: 5000000000, - }, - { - Total: 100000000000, - Free: 90000000000, - }, - }, - }, - }, - }, - expPrintStr: ` -Target: type unknown, state new -- Storage tier 0 (SCM): - Total size: 6.0 GB - Free: 5.0 GB -- Storage tier 1 (NVMe): - Total size: 100 GB - Free: 90 GB -`, - }, - "valid: single target (unknown, drain)": { - pqtr: &control.PoolQueryTargetResp{ - Status: 0, - Infos: []*control.PoolQueryTargetInfo{ - { - Type: 0, - State: control.PoolTargetStateDrain, - Space: []*daos.StorageTargetUsage{ - { - Total: 6000000000, - Free: 5000000000, - }, - { - Total: 100000000000, - Free: 90000000000, - }, - }, - }, - }, - }, - expPrintStr: ` -Target: type unknown, state drain -- Storage tier 0 (SCM): - Total size: 6.0 GB - Free: 5.0 GB -- Storage tier 1 (NVMe): - Total size: 100 GB - Free: 90 GB -`, - }, "valid: multiple target (mixed statuses exclude 2 targets in progress)": { pqtr: &control.PoolQueryTargetResp{ Status: 0, - Infos: []*control.PoolQueryTargetInfo{ + Infos: []*daos.PoolQueryTargetInfo{ { Type: 0, - State: control.PoolTargetStateDown, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDown, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -237,8 +57,8 @@ Target: type unknown, state drain }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -251,8 +71,8 @@ Target: type unknown, state drain }, { Type: 0, - State: control.PoolTargetStateDownOut, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDownOut, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -265,8 +85,8 @@ Target: type unknown, state drain }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -313,11 +133,11 @@ Target: type unknown, state up_in "invalid target state": { pqtr: &control.PoolQueryTargetResp{ Status: 0, - Infos: []*control.PoolQueryTargetInfo{ + Infos: []*daos.PoolQueryTargetInfo{ { Type: 0, State: 42, - Space: []*daos.StorageTargetUsage{ + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -330,8 +150,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -344,8 +164,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateDownOut, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDownOut, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -358,8 +178,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -406,11 +226,11 @@ Target: type unknown, state up_in "invalid target type": { pqtr: &control.PoolQueryTargetResp{ Status: 0, - Infos: []*control.PoolQueryTargetInfo{ + Infos: []*daos.PoolQueryTargetInfo{ { Type: 42, - State: control.PoolTargetStateDown, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDown, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -423,8 +243,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -437,8 +257,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateDownOut, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDownOut, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -451,8 +271,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -499,11 +319,11 @@ Target: type unknown, state up_in "three tiers; third tier unknown StorageMediaType": { pqtr: &control.PoolQueryTargetResp{ Status: 0, - Infos: []*control.PoolQueryTargetInfo{ + Infos: []*daos.PoolQueryTargetInfo{ { Type: 0, - State: control.PoolTargetStateDown, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDown, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -520,8 +340,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -538,8 +358,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateDownOut, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateDownOut, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, @@ -556,8 +376,8 @@ Target: type unknown, state up_in }, { Type: 0, - State: control.PoolTargetStateUpIn, - Space: []*daos.StorageTargetUsage{ + State: daos.PoolTargetStateUpIn, + Space: []*daos.StorageUsageStats{ { Total: 6000000000, Free: 5000000000, diff --git a/src/control/lib/control/pool.go b/src/control/lib/control/pool.go index 060aa7c63dc..4e2a29b745e 100644 --- a/src/control/lib/control/pool.go +++ b/src/control/lib/control/pool.go @@ -461,20 +461,10 @@ type ( Targets []uint32 } - PoolQueryTargetType int32 - PoolQueryTargetState int32 - - // PoolQueryTargetInfo contains information about a single target - PoolQueryTargetInfo struct { - Type PoolQueryTargetType `json:"target_type"` - State PoolQueryTargetState `json:"target_state"` - Space []*daos.StorageTargetUsage - } - // PoolQueryTargetResp contains a pool query target response PoolQueryTargetResp struct { Status int32 `json:"status"` - Infos []*PoolQueryTargetInfo + Infos []*daos.PoolQueryTargetInfo } ) @@ -648,60 +638,12 @@ func PoolQueryTargets(ctx context.Context, rpcClient UnaryInvoker, req *PoolQuer return pqtr, nil } -func (pqtt PoolQueryTargetType) MarshalJSON() ([]byte, error) { - typeStr, ok := mgmtpb.PoolQueryTargetInfo_TargetType_name[int32(pqtt)] - if !ok { - return nil, errors.Errorf("invalid target type %d", pqtt) - } - return []byte(`"` + strings.ToLower(typeStr) + `"`), nil -} - -func (ptt PoolQueryTargetType) String() string { - ptts, ok := mgmtpb.PoolQueryTargetInfo_TargetType_name[int32(ptt)] - if !ok { - return "invalid" - } - return strings.ToLower(ptts) -} - -const ( - PoolTargetStateUnknown PoolQueryTargetState = iota - // PoolTargetStateDownOut indicates the target is not available - PoolTargetStateDownOut - // PoolTargetStateDown indicates the target is not available, may need rebuild - PoolTargetStateDown - // PoolTargetStateUp indicates the target is up - PoolTargetStateUp - // PoolTargetStateUpIn indicates the target is up and running - PoolTargetStateUpIn - // PoolTargetStateNew indicates the target is in an intermediate state (pool map change) - PoolTargetStateNew - // PoolTargetStateDrain indicates the target is being drained - PoolTargetStateDrain -) - -func (pqts PoolQueryTargetState) MarshalJSON() ([]byte, error) { - stateStr, ok := mgmtpb.PoolQueryTargetInfo_TargetState_name[int32(pqts)] - if !ok { - return nil, errors.Errorf("invalid target state %d", pqts) - } - return []byte(`"` + strings.ToLower(stateStr) + `"`), nil -} - -func (pts PoolQueryTargetState) String() string { - ptss, ok := mgmtpb.PoolQueryTargetInfo_TargetState_name[int32(pts)] - if !ok { - return "invalid" - } - return strings.ToLower(ptss) -} - // For using the pretty printer that dmg uses for this target info. -func convertPoolTargetInfo(pbInfo *mgmtpb.PoolQueryTargetInfo) (*PoolQueryTargetInfo, error) { - pqti := new(PoolQueryTargetInfo) - pqti.Type = PoolQueryTargetType(pbInfo.Type) - pqti.State = PoolQueryTargetState(pbInfo.State) - pqti.Space = []*daos.StorageTargetUsage{ +func convertPoolTargetInfo(pbInfo *mgmtpb.PoolQueryTargetInfo) (*daos.PoolQueryTargetInfo, error) { + pqti := new(daos.PoolQueryTargetInfo) + pqti.Type = daos.PoolQueryTargetType(pbInfo.Type) + pqti.State = daos.PoolQueryTargetState(pbInfo.State) + pqti.Space = []*daos.StorageUsageStats{ { Total: uint64(pbInfo.Space[daos.StorageMediaTypeScm].Total), Free: uint64(pbInfo.Space[daos.StorageMediaTypeScm].Free), diff --git a/src/control/lib/daos/pool.go b/src/control/lib/daos/pool.go index e752b58dc25..1a3642d0853 100644 --- a/src/control/lib/daos/pool.go +++ b/src/control/lib/daos/pool.go @@ -7,7 +7,6 @@ package daos import ( - "fmt" "strconv" "strings" @@ -71,6 +70,16 @@ type ( UpgradeLayoutVer uint32 `json:"upgrade_layout_ver"` } + PoolQueryTargetType int32 + PoolQueryTargetState int32 + + // PoolQueryTargetInfo contains information about a single target + PoolQueryTargetInfo struct { + Type PoolQueryTargetType `json:"target_type"` + State PoolQueryTargetState `json:"target_state"` + Space []*StorageUsageStats `json:"space"` + } + // StorageTargetUsage represents DAOS target storage usage StorageTargetUsage struct { Total uint64 `json:"total"` @@ -120,50 +129,53 @@ type PoolServiceState uint const ( // PoolServiceStateCreating indicates that the pool service is being created - PoolServiceStateCreating PoolServiceState = iota + PoolServiceStateCreating = PoolServiceState(mgmtpb.PoolServiceState_Creating) // PoolServiceStateReady indicates that the pool service is ready to be used - PoolServiceStateReady + PoolServiceStateReady = PoolServiceState(mgmtpb.PoolServiceState_Ready) // PoolServiceStateDestroying indicates that the pool service is being destroyed - PoolServiceStateDestroying + PoolServiceStateDestroying = PoolServiceState(mgmtpb.PoolServiceState_Destroying) // PoolServiceStateDegraded indicates that the pool service is in a degraded state - PoolServiceStateDegraded + PoolServiceStateDegraded = PoolServiceState(mgmtpb.PoolServiceState_Degraded) // PoolServiceStateUnknown indicates that the pool service state is unknown - PoolServiceStateUnknown + PoolServiceStateUnknown = PoolServiceState(mgmtpb.PoolServiceState_Unknown) ) func (pss PoolServiceState) String() string { - if pss < PoolServiceStateCreating || pss > PoolServiceStateUnknown { - return fmt.Sprintf("Invalid pool service state %d", pss) + psss, ok := mgmtpb.PoolServiceState_name[int32(pss)] + if !ok { + return "invalid" } - return [...]string{ - mgmtpb.PoolServiceState_Creating.String(), - mgmtpb.PoolServiceState_Ready.String(), - mgmtpb.PoolServiceState_Destroying.String(), - mgmtpb.PoolServiceState_Degraded.String(), - mgmtpb.PoolServiceState_Unknown.String(), - }[pss] + return psss } func (pss PoolServiceState) MarshalJSON() ([]byte, error) { return []byte(`"` + pss.String() + `"`), nil } +func unmarshalStrVal(inStr string, name2Vals map[string]int32, val2Names map[int32]string) (int32, error) { + intVal, found := name2Vals[inStr] + if found { + return intVal, nil + } + // Try converting the string to an int32, to handle the + // conversion from protobuf message using convert.Types(). + val, err := strconv.ParseInt(inStr, 0, 32) + if err != nil { + return 0, errors.Errorf("non-numeric string value %q", inStr) + } + + if _, ok := val2Names[int32(val)]; !ok { + return 0, errors.Errorf("unable to resolve string to value %q", inStr) + } + return int32(val), nil +} + func (pss *PoolServiceState) UnmarshalJSON(data []byte) error { stateStr := strings.Trim(string(data), "\"") - state, ok := mgmtpb.PoolServiceState_value[stateStr] - if !ok { - // Try converting the string to an int32, to handle the - // conversion from protobuf message using convert.Types(). - si, err := strconv.ParseInt(stateStr, 0, 32) - if err != nil { - return errors.Errorf("invalid Pool Service state number parse %q", stateStr) - } - - if _, ok = mgmtpb.PoolServiceState_name[int32(si)]; !ok { - return errors.Errorf("invalid Pool Service state name lookup %q", stateStr) - } - state = int32(si) + state, err := unmarshalStrVal(stateStr, mgmtpb.PoolServiceState_value, mgmtpb.PoolServiceState_name) + if err != nil { + return errors.Wrap(err, "failed to unmarshal PoolServiceState") } *pss = PoolServiceState(state) @@ -175,19 +187,11 @@ type StorageMediaType int32 const ( // StorageMediaTypeScm indicates that the media is storage class (persistent) memory - StorageMediaTypeScm StorageMediaType = iota + StorageMediaTypeScm = StorageMediaType(mgmtpb.StorageMediaType_SCM) // StorageMediaTypeNvme indicates that the media is NVMe SSD - StorageMediaTypeNvme + StorageMediaTypeNvme = StorageMediaType(mgmtpb.StorageMediaType_NVME) ) -func (smt StorageMediaType) MarshalJSON() ([]byte, error) { - typeStr, ok := mgmtpb.StorageMediaType_name[int32(smt)] - if !ok { - return nil, errors.Errorf("invalid storage media type %d", smt) - } - return []byte(`"` + strings.ToLower(typeStr) + `"`), nil -} - func (smt StorageMediaType) String() string { smts, ok := mgmtpb.StorageMediaType_name[int32(smt)] if !ok { @@ -196,16 +200,20 @@ func (smt StorageMediaType) String() string { return strings.ToLower(smts) } +func (smt StorageMediaType) MarshalJSON() ([]byte, error) { + return []byte(`"` + smt.String() + `"`), nil +} + // PoolRebuildState indicates the current state of the pool rebuild process. type PoolRebuildState int32 const ( // PoolRebuildStateIdle indicates that the rebuild process is idle. - PoolRebuildStateIdle PoolRebuildState = iota + PoolRebuildStateIdle = PoolRebuildState(mgmtpb.PoolRebuildStatus_IDLE) // PoolRebuildStateDone indicates that the rebuild process has completed. - PoolRebuildStateDone + PoolRebuildStateDone = PoolRebuildState(mgmtpb.PoolRebuildStatus_DONE) // PoolRebuildStateBusy indicates that the rebuild process is in progress. - PoolRebuildStateBusy + PoolRebuildStateBusy = PoolRebuildState(mgmtpb.PoolRebuildStatus_BUSY) ) func (prs PoolRebuildState) String() string { @@ -217,30 +225,57 @@ func (prs PoolRebuildState) String() string { } func (prs PoolRebuildState) MarshalJSON() ([]byte, error) { - stateStr, ok := mgmtpb.PoolRebuildStatus_State_name[int32(prs)] - if !ok { - return nil, errors.Errorf("invalid rebuild state %d", prs) - } - return []byte(`"` + strings.ToLower(stateStr) + `"`), nil + return []byte(`"` + prs.String() + `"`), nil } func (prs *PoolRebuildState) UnmarshalJSON(data []byte) error { stateStr := strings.ToUpper(string(data)) - state, ok := mgmtpb.PoolRebuildStatus_State_value[stateStr] - if !ok { - // Try converting the string to an int32, to handle the - // conversion from protobuf message using convert.Types(). - si, err := strconv.ParseInt(stateStr, 0, 32) - if err != nil { - return errors.Errorf("invalid rebuild state %q", stateStr) - } - - if _, ok = mgmtpb.PoolRebuildStatus_State_name[int32(si)]; !ok { - return errors.Errorf("invalid rebuild state %q", stateStr) - } - state = int32(si) + + state, err := unmarshalStrVal(stateStr, mgmtpb.PoolRebuildStatus_State_value, mgmtpb.PoolRebuildStatus_State_name) + if err != nil { + return errors.Wrap(err, "failed to unmarshal PoolRebuildState") } *prs = PoolRebuildState(state) return nil } + +func (ptt PoolQueryTargetType) String() string { + ptts, ok := mgmtpb.PoolQueryTargetInfo_TargetType_name[int32(ptt)] + if !ok { + return "invalid" + } + return strings.ToLower(ptts) +} + +func (pqtt PoolQueryTargetType) MarshalJSON() ([]byte, error) { + return []byte(`"` + pqtt.String() + `"`), nil +} + +const ( + PoolTargetStateUnknown = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_STATE_UNKNOWN) + // PoolTargetStateDownOut indicates the target is not available + PoolTargetStateDownOut = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_DOWN_OUT) + // PoolTargetStateDown indicates the target is not available, may need rebuild + PoolTargetStateDown = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_DOWN) + // PoolTargetStateUp indicates the target is up + PoolTargetStateUp = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_UP) + // PoolTargetStateUpIn indicates the target is up and running + PoolTargetStateUpIn = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_UP_IN) + // PoolTargetStateNew indicates the target is in an intermediate state (pool map change) + PoolTargetStateNew = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_NEW) + // PoolTargetStateDrain indicates the target is being drained + PoolTargetStateDrain = PoolQueryTargetState(mgmtpb.PoolQueryTargetInfo_DRAIN) +) + +func (pqts PoolQueryTargetState) String() string { + pqtss, ok := mgmtpb.PoolQueryTargetInfo_TargetState_name[int32(pqts)] + if !ok { + return "invalid" + } + return strings.ToLower(pqtss) +} + +func (pqts PoolQueryTargetState) MarshalJSON() ([]byte, error) { + return []byte(`"` + pqts.String() + `"`), nil +} diff --git a/src/control/system/raft/raft_recovery_test.go b/src/control/system/raft/raft_recovery_test.go index 2ec22a30c5f..211291c26ce 100644 --- a/src/control/system/raft/raft_recovery_test.go +++ b/src/control/system/raft/raft_recovery_test.go @@ -27,7 +27,6 @@ import ( . "github.com/daos-stack/daos/src/control/lib/ranklist" "github.com/daos-stack/daos/src/control/logging" "github.com/daos-stack/daos/src/control/system" - . "github.com/daos-stack/daos/src/control/system" ) var regenRaftFixtures = flag.Bool("regen-raft-fixtures", false, "regenerate raft test files") @@ -103,12 +102,12 @@ func Test_Raft_RegenerateFixtures(t *testing.T) { t.Log("adding ranks") nextAddr := ctrlAddrGen(ctx, net.IPv4(127, 0, 0, 1), 4) for i := 0; i < maxRanks; i++ { - m := &Member{ + m := &system.Member{ Rank: NilRank, UUID: uuid.New(), Addr: <-nextAddr, - State: MemberStateJoined, - FaultDomain: MustCreateFaultDomainFromString("/my/test/domain"), + State: system.MemberStateJoined, + FaultDomain: system.MustCreateFaultDomainFromString("/my/test/domain"), } if err := db.AddMember(m); err != nil { @@ -121,12 +120,12 @@ func Test_Raft_RegenerateFixtures(t *testing.T) { t.Log("adding pools") replicas := replicaGen(ctx, maxRanks, 3) for i := 0; i < maxPools; i++ { - ps := &PoolService{ + ps := &system.PoolService{ PoolUUID: uuid.New(), PoolLabel: fmt.Sprintf("pool%04d", i), State: system.PoolServiceStateReady, Replicas: <-replicas, - Storage: &PoolServiceStorage{ + Storage: &system.PoolServiceStorage{ CreationRankStr: fmt.Sprintf("[0-%d]", maxRanks), CurrentRankStr: fmt.Sprintf("[0-%d]", maxRanks), PerRankTierStorage: []uint64{1, 2},