Skip to content

Commit

Permalink
DAOS-10028 control: Move core types into daos package (#14174)
Browse files Browse the repository at this point in the history
The lib/daos package should be the main repository for
types (e.g. PoolInfo) used throughout the codebase. It
should be possible to import these types without pulling
in extra dependencies (e.g. gRPC, protobufs, etc).

Also reverts an inadvertent change to the system
database's serialization that resulted in 2.4/2.6
incompatibilities.

Required-githooks: true

Change-Id: I2e198a57cc5ae7fe76875c59f2f21eda745ce3e7
Signed-off-by: Michael MacDonald <[email protected]>
  • Loading branch information
mjmac committed May 22, 2024
1 parent c8c9ab0 commit 32bfde0
Show file tree
Hide file tree
Showing 33 changed files with 1,861 additions and 1,552 deletions.
111 changes: 49 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,67 @@ 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.State = daos.PoolServiceStateReady
if poolInfo.DisabledTargets > 0 {
poolInfo.State = daos.PoolServiceStateDegraded
}

poolInfo.Rebuild = convertPoolRebuildStatus(&pinfo.pi_rebuild_st)
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)

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

const (
Expand Down Expand Up @@ -308,46 +299,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 +349,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 +381,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 +393,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

0 comments on commit 32bfde0

Please sign in to comment.