mirror of
https://github.com/kopia/kopia.git
synced 2026-05-03 12:25:32 -04:00
feat(cli): show storage capacity in repo status (#1867)
The connected repository's backing storage capacity and available space can be now retrieved from `kopia repository status`. In text format, these fields are printed in a human friendly form (MiB, GiB). In JSON mode (`--json`), they are output as bytes. Co-authored-by: Shikhar Mall <mall.shikhar.in@gmail.com> Co-authored-by: Julio
This commit is contained in:
@@ -34,6 +34,7 @@ type RepositoryStatus struct {
|
||||
|
||||
ClientOptions repo.ClientOptions `json:"clientOptions"`
|
||||
Storage blob.ConnectionInfo `json:"storage"`
|
||||
Capacity *blob.Capacity `json:"volume,omitempty"`
|
||||
ContentFormat content.FormattingOptions `json:"contentFormat"`
|
||||
ObjectFormat object.Format `json:"objectFormat"`
|
||||
BlobRetention content.BlobCfgBlob `json:"blobRetention"`
|
||||
@@ -50,7 +51,7 @@ func (c *commandRepositoryStatus) setup(svc advancedAppServices, parent commandP
|
||||
c.jo.setup(svc, cmd)
|
||||
}
|
||||
|
||||
func (c *commandRepositoryStatus) outputJSON(r repo.Repository) error {
|
||||
func (c *commandRepositoryStatus) outputJSON(ctx context.Context, r repo.Repository) error {
|
||||
s := RepositoryStatus{
|
||||
ConfigFile: c.svc.repositoryConfigFileName(),
|
||||
ClientOptions: r.ClientOptions(),
|
||||
@@ -64,6 +65,15 @@ func (c *commandRepositoryStatus) outputJSON(r repo.Repository) error {
|
||||
s.BlobRetention = dr.BlobCfg()
|
||||
s.Storage = scrubber.ScrubSensitiveData(reflect.ValueOf(ci)).Interface().(blob.ConnectionInfo) // nolint:forcetypeassert
|
||||
s.ContentFormat = scrubber.ScrubSensitiveData(reflect.ValueOf(dr.ContentReader().ContentFormat())).Interface().(content.FormattingOptions) // nolint:forcetypeassert
|
||||
|
||||
switch cp, err := dr.BlobVolume().GetCapacity(ctx); {
|
||||
case err == nil:
|
||||
s.Capacity = &cp
|
||||
case errors.Is(err, blob.ErrNotAVolume):
|
||||
// This is okay, we will just not populate the result.
|
||||
default:
|
||||
return errors.Wrap(err, "unable to get storage volume capacity")
|
||||
}
|
||||
}
|
||||
|
||||
c.out.printStdout("%s\n", c.jo.jsonBytes(s))
|
||||
@@ -71,9 +81,10 @@ func (c *commandRepositoryStatus) outputJSON(r repo.Repository) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint: funlen
|
||||
func (c *commandRepositoryStatus) run(ctx context.Context, rep repo.Repository) error {
|
||||
if c.jo.jsonOutput {
|
||||
return c.outputJSON(rep)
|
||||
return c.outputJSON(ctx, rep)
|
||||
}
|
||||
|
||||
c.out.printStdout("Config file: %v\n", c.svc.repositoryConfigFileName())
|
||||
@@ -99,6 +110,16 @@ func (c *commandRepositoryStatus) run(ctx context.Context, rep repo.Repository)
|
||||
ci := dr.BlobReader().ConnectionInfo()
|
||||
c.out.printStdout("Storage type: %v\n", ci.Type)
|
||||
|
||||
switch cp, err := dr.BlobVolume().GetCapacity(ctx); {
|
||||
case err == nil:
|
||||
c.out.printStdout("Storage capacity: %v\n", units.BytesStringBase10(int64(cp.SizeB)))
|
||||
c.out.printStdout("Storage available: %v\n", units.BytesStringBase10(int64(cp.FreeB)))
|
||||
case errors.Is(err, blob.ErrNotAVolume):
|
||||
c.out.printStdout("Storage capacity: unbounded\n")
|
||||
default:
|
||||
return errors.Wrap(err, "unable to get storage volume capacity")
|
||||
}
|
||||
|
||||
if cjson, err := json.MarshalIndent(scrubber.ScrubSensitiveData(reflect.ValueOf(ci.Config)).Interface(), " ", " "); err == nil {
|
||||
c.out.printStdout("Storage config: %v\n", string(cjson))
|
||||
}
|
||||
|
||||
@@ -56,9 +56,9 @@ type OutputBuffer interface {
|
||||
// Capacity describes the storage capacity and usage of a Volume.
|
||||
type Capacity struct {
|
||||
// Size of volume in bytes.
|
||||
SizeB uint64
|
||||
SizeB uint64 `json:"capacity,omitempty"`
|
||||
// Available (writeable) space in bytes.
|
||||
FreeB uint64
|
||||
FreeB uint64 `json:"available"`
|
||||
}
|
||||
|
||||
// Volume defines disk/volume access API to blob storage.
|
||||
|
||||
@@ -50,6 +50,7 @@ type DirectRepository interface {
|
||||
ObjectFormat() object.Format
|
||||
BlobCfg() content.BlobCfgBlob
|
||||
BlobReader() blob.Reader
|
||||
BlobVolume() blob.Volume
|
||||
ContentReader() content.Reader
|
||||
IndexBlobs(ctx context.Context, includeInactive bool) ([]content.IndexBlobInfo, error)
|
||||
Crypter() *content.Crypter
|
||||
@@ -308,6 +309,11 @@ func (r *directRepository) BlobReader() blob.Reader {
|
||||
return r.blobs
|
||||
}
|
||||
|
||||
// BlobVolume returns the blob volume interface.
|
||||
func (r *directRepository) BlobVolume() blob.Volume {
|
||||
return r.blobs
|
||||
}
|
||||
|
||||
// ContentReader returns the content reader.
|
||||
func (r *directRepository) ContentReader() content.Reader {
|
||||
return r.cmgr
|
||||
|
||||
Reference in New Issue
Block a user