mirror of
https://github.com/ceph/go-ceph
synced 2024-12-25 23:52:27 +00:00
ae44f69791
It appears the JSON being returned from `ceph fs status` has changed. The field returning the mds version was previously "just" a string. Now its a more complex thing. This of course breaks the old version of the go code which is statically typed to expect a string. In order not to break backwards compatibility we replace the object used for parsing the JSON with a private object that has a custom unmarshaller function for the mds version field. If it sees the string it uses the string. Otherwise, it looks for this new structure and, if possible, extracts the version string from the first item. Signed-off-by: John Mulligan <jmulligan@redhat.com>
184 lines
4.8 KiB
Go
184 lines
4.8 KiB
Go
package admin
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
)
|
|
|
|
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:
|
|
// ceph fs volume ls
|
|
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:
|
|
// ceph fs ls
|
|
func (fsa *FSAdmin) ListFileSystems() ([]FSPoolInfo, error) {
|
|
res := fsa.rawMonCommand(listFsCmd)
|
|
return parseFsList(res)
|
|
}
|
|
|
|
func parseFsList(res response) ([]FSPoolInfo, error) {
|
|
var listing []FSPoolInfo
|
|
if err := res.NoStatus().Unmarshal(&listing).End(); err != nil {
|
|
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
|
|
if err := res.FilterPrefix(dumpOkPrefix).NoStatus().Unmarshal(&dump).End(); err != nil {
|
|
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"`
|
|
}
|
|
|
|
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
|
|
res = res.NoStatus()
|
|
if !res.Ok() {
|
|
return nil, res.End()
|
|
}
|
|
res = res.Unmarshal(&vs)
|
|
if !res.Ok() {
|
|
if bytes.HasPrefix(res.Body(), []byte("ceph")) {
|
|
return nil, NotImplementedError{
|
|
Response: newResponse(res.Body(), invalidTextualResponse, res.Unwrap()),
|
|
}
|
|
}
|
|
return nil, res.End()
|
|
}
|
|
return &vs, nil
|
|
}
|
|
|
|
// VolumeStatus returns a VolumeStatus object for the given volume name.
|
|
//
|
|
// Similar To:
|
|
// ceph fs status cephfs <name>
|
|
func (fsa *FSAdmin) VolumeStatus(name string) (*VolumeStatus, error) {
|
|
res := fsa.marshalMgrCommand(map[string]string{
|
|
"fs": name,
|
|
"prefix": "fs status",
|
|
"format": "json",
|
|
})
|
|
v, err := parseVolumeStatus(res)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return v.volumeStatus(), nil
|
|
}
|