Skip to content

Commit

Permalink
DAOS-10028 client: Add Go bindings for libdaos (Pool)
Browse files Browse the repository at this point in the history
Continue the work of converting the raw cgo in the daos
tool into proper Go bindings for libdaos. This patch
covers pool functionality.

Features: daos_cmd pool
Required-githooks: true
Signed-off-by: Michael MacDonald <[email protected]>
  • Loading branch information
mjmac committed Dec 22, 2024
1 parent 8984dd6 commit d94cc38
Show file tree
Hide file tree
Showing 24 changed files with 3,054 additions and 497 deletions.
94 changes: 12 additions & 82 deletions src/control/cmd/daos/attribute.go
Original file line number Diff line number Diff line change
@@ -1,95 +1,35 @@
//
// (C) Copyright 2018-2021 Intel Corporation.
// (C) Copyright 2018-2024 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//

package main

import (
"fmt"
"io"
"unsafe"

"github.com/daos-stack/daos/src/control/lib/daos"
"github.com/pkg/errors"

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

/*
#include "util.h"
*/
import "C"

type (
attribute struct {
Name string `json:"name"`
Value []byte `json:"value,omitempty"`
}

attrList []*attribute
)

func (al attrList) asMap() map[string][]byte {
m := make(map[string][]byte)
for _, a := range al {
m[a.Name] = a.Value
}
return m
}

func (al attrList) asList() []string {
names := make([]string, len(al))
for i, a := range al {
names[i] = a.Name
}
return names
}

func printAttributes(out io.Writer, header string, attrs ...*attribute) {
fmt.Fprintf(out, "%s\n", header)

if len(attrs) == 0 {
fmt.Fprintln(out, " No attributes found.")
return
}

nameTitle := "Name"
valueTitle := "Value"
titles := []string{nameTitle}

table := []txtfmt.TableRow{}
for _, attr := range attrs {
row := txtfmt.TableRow{}
row[nameTitle] = attr.Name
if len(attr.Value) != 0 {
row[valueTitle] = string(attr.Value)
if len(titles) == 1 {
titles = append(titles, valueTitle)
}
}
table = append(table, row)
}

tf := txtfmt.NewTableFormatter(titles...)
tf.InitWriter(out)
tf.Format(table)
}

type attrType int

const (
poolAttr attrType = iota
contAttr
)

func listDaosAttributes(hdl C.daos_handle_t, at attrType, verbose bool) (attrList, error) {
func listDaosAttributes(hdl C.daos_handle_t, at attrType, verbose bool) (daos.AttributeList, error) {
var rc C.int
expectedSize, totalSize := C.size_t(0), C.size_t(0)

switch at {
case poolAttr:
rc = C.daos_pool_list_attr(hdl, nil, &totalSize, nil)
case contAttr:
rc = C.daos_cont_list_attr(hdl, nil, &totalSize, nil)
default:
Expand All @@ -109,8 +49,6 @@ func listDaosAttributes(hdl C.daos_handle_t, at attrType, verbose bool) (attrLis
defer C.free(buf)

switch at {
case poolAttr:
rc = C.daos_pool_list_attr(hdl, (*C.char)(buf), &totalSize, nil)
case contAttr:
rc = C.daos_cont_list_attr(hdl, (*C.char)(buf), &totalSize, nil)
default:
Expand All @@ -130,9 +68,9 @@ func listDaosAttributes(hdl C.daos_handle_t, at attrType, verbose bool) (attrLis
return getDaosAttributes(hdl, at, attrNames)
}

attrs := make([]*attribute, len(attrNames))
attrs := make(daos.AttributeList, len(attrNames))
for i, name := range attrNames {
attrs[i] = &attribute{Name: name}
attrs[i] = &daos.Attribute{Name: name}
}

return attrs, nil
Expand All @@ -141,7 +79,7 @@ func listDaosAttributes(hdl C.daos_handle_t, at attrType, verbose bool) (attrLis

// getDaosAttributes fetches the values for the given list of attribute names.
// Uses the bulk attribute fetch API to minimize roundtrips.
func getDaosAttributes(hdl C.daos_handle_t, at attrType, names []string) (attrList, error) {
func getDaosAttributes(hdl C.daos_handle_t, at attrType, names []string) (daos.AttributeList, error) {
if len(names) == 0 {
attrList, err := listDaosAttributes(hdl, at, false)
if err != nil {
Expand Down Expand Up @@ -171,8 +109,6 @@ func getDaosAttributes(hdl C.daos_handle_t, at attrType, names []string) (attrLi
attrSizes := make([]C.size_t, numAttr)
var rc C.int
switch at {
case poolAttr:
rc = C.daos_pool_get_attr(hdl, C.int(numAttr), &attrNames[0], nil, &attrSizes[0], nil)
case contAttr:
rc = C.daos_cont_get_attr(hdl, C.int(numAttr), &attrNames[0], nil, &attrSizes[0], nil)
default:
Expand All @@ -199,8 +135,6 @@ func getDaosAttributes(hdl C.daos_handle_t, at attrType, names []string) (attrLi

// Do the actual fetch of all values in one go.
switch at {
case poolAttr:
rc = C.daos_pool_get_attr(hdl, C.int(numAttr), &attrNames[0], &attrValues[0], &attrSizes[0], nil)
case contAttr:
rc = C.daos_cont_get_attr(hdl, C.int(numAttr), &attrNames[0], &attrValues[0], &attrSizes[0], nil)
default:
Expand All @@ -214,9 +148,9 @@ func getDaosAttributes(hdl C.daos_handle_t, at attrType, names []string) (attrLi
// Note that we are copying the values into Go-managed byte slices
// for safety and simplicity so that we can free the C memory as soon
// as this function exits.
attrs := make([]*attribute, numAttr)
attrs := make(daos.AttributeList, numAttr)
for i, name := range names {
attrs[i] = &attribute{
attrs[i] = &daos.Attribute{
Name: name,
Value: C.GoBytes(attrValues[i], C.int(attrSizes[i])),
}
Expand All @@ -228,7 +162,7 @@ func getDaosAttributes(hdl C.daos_handle_t, at attrType, names []string) (attrLi
// getDaosAttribute fetches the value for the given attribute name.
// NB: For operations involving multiple attributes, the getDaosAttributes()
// function is preferred for efficiency.
func getDaosAttribute(hdl C.daos_handle_t, at attrType, name string) (*attribute, error) {
func getDaosAttribute(hdl C.daos_handle_t, at attrType, name string) (*daos.Attribute, error) {
attrs, err := getDaosAttributes(hdl, at, []string{name})
if err != nil {
return nil, err
Expand All @@ -241,7 +175,7 @@ func getDaosAttribute(hdl C.daos_handle_t, at attrType, name string) (*attribute

// setDaosAttributes sets the values for the given list of attribute names.
// Uses the bulk attribute set API to minimize roundtrips.
func setDaosAttributes(hdl C.daos_handle_t, at attrType, attrs attrList) error {
func setDaosAttributes(hdl C.daos_handle_t, at attrType, attrs daos.AttributeList) error {
if len(attrs) == 0 {
return nil
}
Expand Down Expand Up @@ -277,8 +211,6 @@ func setDaosAttributes(hdl C.daos_handle_t, at attrType, attrs attrList) error {
attrCount := C.int(len(attrs))
var rc C.int
switch at {
case poolAttr:
rc = C.daos_pool_set_attr(hdl, attrCount, &attrNames[0], &valBufs[0], &valSizes[0], nil)
case contAttr:
rc = C.daos_cont_set_attr(hdl, attrCount, &attrNames[0], &valBufs[0], &valSizes[0], nil)
default:
Expand All @@ -291,12 +223,12 @@ func setDaosAttributes(hdl C.daos_handle_t, at attrType, attrs attrList) error {
// setDaosAttribute sets the value for the given attribute name.
// NB: For operations involving multiple attributes, the setDaosAttributes()
// function is preferred for efficiency.
func setDaosAttribute(hdl C.daos_handle_t, at attrType, attr *attribute) error {
func setDaosAttribute(hdl C.daos_handle_t, at attrType, attr *daos.Attribute) error {
if attr == nil {
return errors.Errorf("nil %T", attr)
}

return setDaosAttributes(hdl, at, attrList{attr})
return setDaosAttributes(hdl, at, daos.AttributeList{attr})
}

func delDaosAttribute(hdl C.daos_handle_t, at attrType, name string) error {
Expand All @@ -305,8 +237,6 @@ func delDaosAttribute(hdl C.daos_handle_t, at attrType, name string) error {

var rc C.int
switch at {
case poolAttr:
rc = C.daos_pool_del_attr(hdl, 1, &attrName, nil)
case contAttr:
rc = C.daos_cont_del_attr(hdl, 1, &attrName, nil)
default:
Expand Down
41 changes: 21 additions & 20 deletions src/control/cmd/daos/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/jessevdk/go-flags"
"github.com/pkg/errors"

"github.com/daos-stack/daos/src/control/cmd/daos/pretty"
"github.com/daos-stack/daos/src/control/lib/daos"
"github.com/daos-stack/daos/src/control/lib/txtfmt"
"github.com/daos-stack/daos/src/control/lib/ui"
Expand Down Expand Up @@ -221,14 +222,14 @@ func queryContainer(poolUUID, contUUID uuid.UUID, poolHandle, contHandle C.daos_
return ci, nil
}

func (cmd *containerBaseCmd) connectPool(flags C.uint, ap *C.struct_cmd_args_s) (func(), error) {
func (cmd *containerBaseCmd) connectPool(flags daos.PoolConnectFlag, ap *C.struct_cmd_args_s) (func(), error) {
if err := cmd.poolBaseCmd.connectPool(flags); err != nil {
return nil, err
}

if ap != nil {
ap.pool = cmd.cPoolHandle
if err := copyUUID(&ap.p_uuid, cmd.poolUUID); err != nil {
if err := copyUUID(&ap.p_uuid, cmd.pool.UUID()); err != nil {
cmd.disconnectPool()
return nil, err
}
Expand Down Expand Up @@ -299,7 +300,7 @@ func (cmd *containerCreateCmd) Execute(_ []string) (err error) {
cmd.poolBaseCmd.Args.Pool.UUID = pu
}

disconnectPool, err := cmd.connectPool(C.DAOS_PC_RW, ap)
disconnectPool, err := cmd.connectPool(daos.PoolConnectFlagReadWrite, ap)
if err != nil {
return err
}
Expand All @@ -317,7 +318,7 @@ func (cmd *containerCreateCmd) Execute(_ []string) (err error) {
defer cmd.closeContainer()

var ci *daos.ContainerInfo
ci, err = queryContainer(cmd.poolUUID, cmd.contUUID, cmd.cPoolHandle, cmd.cContHandle)
ci, err = queryContainer(cmd.pool.UUID(), cmd.contUUID, cmd.cPoolHandle, cmd.cContHandle)
if err != nil {
if errors.Cause(err) != daos.NoPermission {
return errors.Wrapf(err, "failed to query new container %s", contID)
Expand All @@ -327,7 +328,7 @@ func (cmd *containerCreateCmd) Execute(_ []string) (err error) {
cmd.Errorf("container %s was created, but query failed", contID)

ci = new(daos.ContainerInfo)
ci.PoolUUID = cmd.poolUUID
ci.PoolUUID = cmd.pool.UUID()
ci.Type = cmd.Type.String()
ci.ContainerUUID = cmd.contUUID
ci.ContainerLabel = cmd.Args.Label
Expand Down Expand Up @@ -406,9 +407,9 @@ func (cmd *containerCreateCmd) contCreate() (string, error) {
}

if len(cmd.Attrs.ParsedProps) != 0 {
attrs := make(attrList, 0, len(cmd.Attrs.ParsedProps))
attrs := make(daos.AttributeList, 0, len(cmd.Attrs.ParsedProps))
for key, val := range cmd.Attrs.ParsedProps {
attrs = append(attrs, &attribute{
attrs = append(attrs, &daos.Attribute{
Name: key,
Value: []byte(val),
})
Expand Down Expand Up @@ -575,7 +576,7 @@ func (cmd *existingContainerCmd) resolveContainerPath(ap *C.struct_cmd_args_s) (
if err != nil {
return
}
cmd.poolBaseCmd.poolUUID = cmd.poolBaseCmd.Args.Pool.UUID
//cmd.poolBaseCmd.poolUUID = cmd.poolBaseCmd.Args.Pool.UUID
cmd.poolBaseCmd.Args.Pool.Label = C.GoString(&ap.pool_str[0])

cmd.Args.Container.UUID, err = uuidFromC(ap.c_uuid)
Expand Down Expand Up @@ -627,7 +628,7 @@ func (cmd *existingContainerCmd) resolveAndConnect(contFlags C.uint, ap *C.struc
}

var cleanupPool func()
cleanupPool, err = cmd.connectPool(C.DAOS_PC_RO, ap)
cleanupPool, err = cmd.connectPool(daos.PoolConnectFlagReadOnly, ap)
if err != nil {
return
}
Expand All @@ -651,7 +652,7 @@ func (cmd *existingContainerCmd) resolveAndConnect(contFlags C.uint, ap *C.struc
}, nil
}

func (cmd *existingContainerCmd) getAttr(name string) (*attribute, error) {
func (cmd *existingContainerCmd) getAttr(name string) (*daos.Attribute, error) {
return getDaosAttribute(cmd.cContHandle, contAttr, name)
}

Expand Down Expand Up @@ -731,7 +732,7 @@ func printContainers(out io.Writer, contIDs []*ContainerID) {
}

func (cmd *containerListCmd) Execute(_ []string) error {
cleanup, err := cmd.resolveAndConnect(C.DAOS_PC_RO, nil)
cleanup, err := cmd.resolveAndConnect(daos.PoolConnectFlagReadOnly, nil)
if err != nil {
return err
}
Expand Down Expand Up @@ -990,7 +991,7 @@ func (cmd *containerQueryCmd) Execute(_ []string) error {
}
defer cleanup()

ci, err := queryContainer(cmd.poolUUID, cmd.contUUID, cmd.cPoolHandle, cmd.cContHandle)
ci, err := queryContainer(cmd.pool.UUID(), cmd.contUUID, cmd.cPoolHandle, cmd.cContHandle)
if err != nil {
return errors.Wrapf(err,
"failed to query container %s",
Expand Down Expand Up @@ -1123,14 +1124,14 @@ func (cmd *containerListAttrsCmd) Execute(args []string) error {

if cmd.JSONOutputEnabled() {
if cmd.Verbose {
return cmd.OutputJSON(attrs.asMap(), nil)
return cmd.OutputJSON(attrs.AsMap(), nil)
}
return cmd.OutputJSON(attrs.asList(), nil)
return cmd.OutputJSON(attrs.AsList(), nil)
}

var bld strings.Builder
title := fmt.Sprintf("Attributes for container %s:", cmd.ContainerID())
printAttributes(&bld, title, attrs...)
pretty.PrintAttributes(&bld, title, attrs...)

cmd.Info(bld.String())

Expand Down Expand Up @@ -1208,7 +1209,7 @@ func (cmd *containerGetAttrCmd) Execute(args []string) error {
}
defer cleanup()

var attrs attrList
var attrs daos.AttributeList
if len(cmd.Args.Attrs.ParsedProps) == 0 {
attrs, err = listDaosAttributes(cmd.cContHandle, contAttr, true)
} else {
Expand All @@ -1229,7 +1230,7 @@ func (cmd *containerGetAttrCmd) Execute(args []string) error {

var bld strings.Builder
title := fmt.Sprintf("Attributes for container %s:", cmd.ContainerID())
printAttributes(&bld, title, attrs...)
pretty.PrintAttributes(&bld, title, attrs...)

cmd.Info(bld.String())

Expand Down Expand Up @@ -1278,9 +1279,9 @@ func (cmd *containerSetAttrCmd) Execute(args []string) error {
}
defer cleanup()

attrs := make(attrList, 0, len(cmd.Args.Attrs.ParsedProps))
attrs := make(daos.AttributeList, 0, len(cmd.Args.Attrs.ParsedProps))
for key, val := range cmd.Args.Attrs.ParsedProps {
attrs = append(attrs, &attribute{
attrs = append(attrs, &daos.Attribute{
Name: key,
Value: []byte(val),
})
Expand Down Expand Up @@ -1472,7 +1473,7 @@ func (f *ContainerID) Complete(match string) (comps []flags.Completion) {
}
defer fini()

cleanup, err := pf.resolveAndConnect(C.DAOS_PC_RO, nil)
cleanup, err := pf.resolveAndConnect(daos.PoolConnectFlagReadOnly, nil)
if err != nil {
return
}
Expand Down
Loading

0 comments on commit d94cc38

Please sign in to comment.