2020-10-14 06:22:20 +00:00
|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strconv"
|
|
|
|
|
2021-06-09 04:54:52 +00:00
|
|
|
ccom "github.com/ceph/go-ceph/common/commands"
|
|
|
|
"github.com/ceph/go-ceph/internal/commands"
|
2020-10-14 06:22:20 +00:00
|
|
|
"github.com/ceph/go-ceph/rados"
|
|
|
|
)
|
|
|
|
|
|
|
|
// RadosCommander provides an interface to execute JSON-formatted commands that
|
|
|
|
// allow the cephfs administrative functions to interact with the Ceph cluster.
|
2021-06-09 04:54:52 +00:00
|
|
|
type RadosCommander = ccom.RadosCommander
|
2020-10-14 06:22:20 +00:00
|
|
|
|
|
|
|
// FSAdmin is used to administrate CephFS within a ceph cluster.
|
|
|
|
type FSAdmin struct {
|
|
|
|
conn RadosCommander
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates an FSAdmin automatically based on the default ceph
|
|
|
|
// configuration file. If more customization is needed, create a
|
|
|
|
// *rados.Conn as you see fit and use NewFromConn to use that
|
|
|
|
// connection with these administrative functions.
|
2023-04-26 07:05:57 +00:00
|
|
|
//
|
|
|
|
// Deprecated: Use NewFromConn instead of New. The New function does not expose
|
|
|
|
// the rados connection and therefore can not be deterministically cleaned up.
|
2020-10-14 06:22:20 +00:00
|
|
|
func New() (*FSAdmin, error) {
|
|
|
|
conn, err := rados.NewConn()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = conn.ReadDefaultConfigFile()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = conn.Connect()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return NewFromConn(conn), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewFromConn creates an FSAdmin management object from a preexisting
|
|
|
|
// rados connection. The existing connection can be rados.Conn or any
|
|
|
|
// type implementing the RadosCommander interface. This may be useful
|
|
|
|
// if the calling layer needs to inject additional logging, error handling,
|
|
|
|
// fault injection, etc.
|
|
|
|
func NewFromConn(conn RadosCommander) *FSAdmin {
|
|
|
|
return &FSAdmin{conn}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fsa *FSAdmin) validate() error {
|
|
|
|
if fsa.conn == nil {
|
|
|
|
return rados.ErrNotConnected
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// rawMgrCommand takes a byte buffer and sends it to the MGR as a command.
|
|
|
|
// The buffer is expected to contain preformatted JSON.
|
|
|
|
func (fsa *FSAdmin) rawMgrCommand(buf []byte) response {
|
2021-06-09 04:54:52 +00:00
|
|
|
return commands.RawMgrCommand(fsa.conn, buf)
|
2020-10-14 06:22:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// marshalMgrCommand takes an generic interface{} value, converts it to JSON and
|
|
|
|
// sends the json to the MGR as a command.
|
|
|
|
func (fsa *FSAdmin) marshalMgrCommand(v interface{}) response {
|
2021-06-09 04:54:52 +00:00
|
|
|
return commands.MarshalMgrCommand(fsa.conn, v)
|
2020-10-14 06:22:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// rawMonCommand takes a byte buffer and sends it to the MON as a command.
|
|
|
|
// The buffer is expected to contain preformatted JSON.
|
|
|
|
func (fsa *FSAdmin) rawMonCommand(buf []byte) response {
|
2021-06-09 04:54:52 +00:00
|
|
|
return commands.RawMonCommand(fsa.conn, buf)
|
2020-10-14 06:22:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// marshalMonCommand takes an generic interface{} value, converts it to JSON and
|
|
|
|
// sends the json to the MGR as a command.
|
|
|
|
func (fsa *FSAdmin) marshalMonCommand(v interface{}) response {
|
2021-06-09 04:54:52 +00:00
|
|
|
return commands.MarshalMonCommand(fsa.conn, v)
|
2020-10-14 06:22:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type listNamedResult struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseListNames(res response) ([]string, error) {
|
|
|
|
var r []listNamedResult
|
2021-06-09 04:54:52 +00:00
|
|
|
if err := res.NoStatus().Unmarshal(&r).End(); err != nil {
|
2020-10-14 06:22:20 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
vl := make([]string, len(r))
|
|
|
|
for i := range r {
|
|
|
|
vl[i] = r[i].Name
|
|
|
|
}
|
|
|
|
return vl, nil
|
|
|
|
}
|
|
|
|
|
2022-06-15 05:34:25 +00:00
|
|
|
func parseListKeyValues(res response) (map[string]string, error) {
|
|
|
|
var x map[string]string
|
|
|
|
if err := res.NoStatus().Unmarshal(&x).End(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return x, nil
|
|
|
|
}
|
|
|
|
|
2020-10-14 06:22:20 +00:00
|
|
|
// parsePathResponse returns a cleaned up path from requests that get a path
|
|
|
|
// unless an error is encountered, then an error is returned.
|
|
|
|
func parsePathResponse(res response) (string, error) {
|
2021-06-09 04:54:52 +00:00
|
|
|
if res2 := res.NoStatus(); !res2.Ok() {
|
2020-10-14 06:22:20 +00:00
|
|
|
return "", res.End()
|
|
|
|
}
|
2021-06-09 04:54:52 +00:00
|
|
|
b := res.Body()
|
2020-10-14 06:22:20 +00:00
|
|
|
// if there's a trailing newline in the buffer strip it.
|
|
|
|
// ceph assumes a CLI wants the output of the buffer and there's
|
|
|
|
// no format=json mode available currently.
|
|
|
|
for len(b) >= 1 && b[len(b)-1] == '\n' {
|
|
|
|
b = b[:len(b)-1]
|
|
|
|
}
|
|
|
|
return string(b), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// modeString converts a unix-style mode value to a string-ified version in an
|
|
|
|
// octal representation (e.g. "777", "700", etc). This format is expected by
|
|
|
|
// some of the ceph JSON command inputs.
|
|
|
|
func modeString(m int, force bool) string {
|
|
|
|
if force || m != 0 {
|
|
|
|
return strconv.FormatInt(int64(m), 8)
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// uint64String converts a uint64 to a string. Some of the ceph json commands
|
|
|
|
// can take a string or "int" (as a string). This is a common function for
|
|
|
|
// doing that conversion.
|
|
|
|
func uint64String(v uint64) string {
|
|
|
|
return strconv.FormatUint(uint64(v), 10)
|
|
|
|
}
|