2020-10-14 06:22:20 +00:00
|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2022-06-15 05:34:25 +00:00
|
|
|
"encoding/json"
|
2020-10-14 06:22:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
listVolumesCmd = []byte(`{"prefix":"fs volume ls"}`)
|
|
|
|
dumpVolumesCmd = []byte(`{"prefix":"fs dump","format":"json"}`)
|
|
|
|
listFsCmd = []byte(`{"prefix":"fs ls","format":"json"}`)
|
|
|
|
)
|
|
|
|
|
|
|
|
// ListVolumes return a list of volumes in this Ceph cluster.
|
|
|
|
//
|
|
|
|
// Similar To:
|
2023-04-26 07:05:57 +00:00
|
|
|
//
|
|
|
|
// ceph fs volume ls
|
2020-10-14 06:22:20 +00:00
|
|
|
func (fsa *FSAdmin) ListVolumes() ([]string, error) {
|
|
|
|
res := fsa.rawMgrCommand(listVolumesCmd)
|
|
|
|
return parseListNames(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FSPoolInfo contains the name of a file system as well as the metadata and
|
|
|
|
// data pools. Pool information is available by ID or by name.
|
|
|
|
type FSPoolInfo struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
MetadataPool string `json:"metadata_pool"`
|
|
|
|
MetadataPoolID int `json:"metadata_pool_id"`
|
|
|
|
DataPools []string `json:"data_pools"`
|
|
|
|
DataPoolIDs []int `json:"data_pool_ids"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListFileSystems lists file systems along with the pools occupied by those
|
|
|
|
// file systems.
|
|
|
|
//
|
|
|
|
// Similar To:
|
2023-04-26 07:05:57 +00:00
|
|
|
//
|
|
|
|
// ceph fs ls
|
2020-10-14 06:22:20 +00:00
|
|
|
func (fsa *FSAdmin) ListFileSystems() ([]FSPoolInfo, error) {
|
|
|
|
res := fsa.rawMonCommand(listFsCmd)
|
|
|
|
return parseFsList(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseFsList(res response) ([]FSPoolInfo, error) {
|
|
|
|
var listing []FSPoolInfo
|
2021-06-09 04:54:52 +00:00
|
|
|
if err := res.NoStatus().Unmarshal(&listing).End(); err != nil {
|
2020-10-14 06:22:20 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return listing, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// VolumeIdent contains a pair of file system identifying values: the volume
|
|
|
|
// name and the volume ID.
|
|
|
|
type VolumeIdent struct {
|
|
|
|
Name string
|
|
|
|
ID int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type cephFileSystem struct {
|
|
|
|
ID int64 `json:"id"`
|
|
|
|
MDSMap struct {
|
|
|
|
FSName string `json:"fs_name"`
|
|
|
|
} `json:"mdsmap"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type fsDump struct {
|
|
|
|
FileSystems []cephFileSystem `json:"filesystems"`
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
dumpOkPrefix = "dumped fsmap epoch"
|
|
|
|
dumpOkLen = len(dumpOkPrefix)
|
|
|
|
|
|
|
|
invalidTextualResponse = "this ceph version returns a non-parsable volume status response"
|
|
|
|
)
|
|
|
|
|
|
|
|
func parseDumpToIdents(res response) ([]VolumeIdent, error) {
|
|
|
|
if !res.Ok() {
|
|
|
|
return nil, res.End()
|
|
|
|
}
|
|
|
|
var dump fsDump
|
2021-06-09 04:54:52 +00:00
|
|
|
if err := res.FilterPrefix(dumpOkPrefix).NoStatus().Unmarshal(&dump).End(); err != nil {
|
2020-10-14 06:22:20 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// copy the dump json into the simpler enumeration list
|
|
|
|
idents := make([]VolumeIdent, len(dump.FileSystems))
|
|
|
|
for i := range dump.FileSystems {
|
|
|
|
idents[i].ID = dump.FileSystems[i].ID
|
|
|
|
idents[i].Name = dump.FileSystems[i].MDSMap.FSName
|
|
|
|
}
|
|
|
|
return idents, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnumerateVolumes returns a list of volume-name volume-id pairs.
|
|
|
|
func (fsa *FSAdmin) EnumerateVolumes() ([]VolumeIdent, error) {
|
|
|
|
// We base our enumeration on the ceph fs dump json. This may not be the
|
|
|
|
// only way to do it, but it's the only one I know of currently. Because of
|
|
|
|
// this and to keep our initial implementation simple, we expose our own
|
|
|
|
// simplified type only, rather do a partial implementation of dump.
|
|
|
|
return parseDumpToIdents(fsa.rawMonCommand(dumpVolumesCmd))
|
|
|
|
}
|
|
|
|
|
|
|
|
// VolumePool reports on the pool status for a CephFS volume.
|
|
|
|
type VolumePool struct {
|
|
|
|
ID int `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
Available uint64 `json:"avail"`
|
|
|
|
Used uint64 `json:"used"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// VolumeStatus reports various properties of a CephFS volume.
|
|
|
|
// TODO: Fill in.
|
|
|
|
type VolumeStatus struct {
|
|
|
|
MDSVersion string `json:"mds_version"`
|
|
|
|
Pools []VolumePool `json:"pools"`
|
|
|
|
}
|
|
|
|
|
2022-06-15 05:34:25 +00:00
|
|
|
type mdsVersionField struct {
|
|
|
|
Version string
|
|
|
|
Items []struct {
|
|
|
|
Version string `json:"version"`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mdsVersionField) UnmarshalJSON(data []byte) (err error) {
|
|
|
|
if err = json.Unmarshal(data, &m.Version); err == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return json.Unmarshal(data, &m.Items)
|
|
|
|
}
|
|
|
|
|
|
|
|
// volumeStatusResponse deals with the changing output of the mgr
|
|
|
|
// api json
|
|
|
|
type volumeStatusResponse struct {
|
|
|
|
Pools []VolumePool `json:"pools"`
|
|
|
|
MDSVersion mdsVersionField `json:"mds_version"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *volumeStatusResponse) volumeStatus() *VolumeStatus {
|
|
|
|
vstatus := &VolumeStatus{}
|
|
|
|
vstatus.Pools = v.Pools
|
|
|
|
if v.MDSVersion.Version != "" {
|
|
|
|
vstatus.MDSVersion = v.MDSVersion.Version
|
|
|
|
} else if len(v.MDSVersion.Items) > 0 {
|
|
|
|
vstatus.MDSVersion = v.MDSVersion.Items[0].Version
|
|
|
|
}
|
|
|
|
return vstatus
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseVolumeStatus(res response) (*volumeStatusResponse, error) {
|
|
|
|
var vs volumeStatusResponse
|
2021-06-09 04:54:52 +00:00
|
|
|
res = res.NoStatus()
|
2020-10-14 06:22:20 +00:00
|
|
|
if !res.Ok() {
|
|
|
|
return nil, res.End()
|
|
|
|
}
|
2021-06-09 04:54:52 +00:00
|
|
|
res = res.Unmarshal(&vs)
|
2020-10-14 06:22:20 +00:00
|
|
|
if !res.Ok() {
|
2021-06-09 04:54:52 +00:00
|
|
|
if bytes.HasPrefix(res.Body(), []byte("ceph")) {
|
|
|
|
return nil, NotImplementedError{
|
|
|
|
Response: newResponse(res.Body(), invalidTextualResponse, res.Unwrap()),
|
|
|
|
}
|
2020-10-14 06:22:20 +00:00
|
|
|
}
|
|
|
|
return nil, res.End()
|
|
|
|
}
|
|
|
|
return &vs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// VolumeStatus returns a VolumeStatus object for the given volume name.
|
|
|
|
//
|
|
|
|
// Similar To:
|
2023-04-26 07:05:57 +00:00
|
|
|
//
|
|
|
|
// ceph fs status cephfs <name>
|
2020-10-14 06:22:20 +00:00
|
|
|
func (fsa *FSAdmin) VolumeStatus(name string) (*VolumeStatus, error) {
|
|
|
|
res := fsa.marshalMgrCommand(map[string]string{
|
|
|
|
"fs": name,
|
|
|
|
"prefix": "fs status",
|
|
|
|
"format": "json",
|
|
|
|
})
|
2022-06-15 05:34:25 +00:00
|
|
|
v, err := parseVolumeStatus(res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return v.volumeStatus(), nil
|
2020-10-14 06:22:20 +00:00
|
|
|
}
|