diff --git a/src/runtime/virtcontainers/agent.go b/src/runtime/virtcontainers/agent.go index a7888552b5..0d6d6b7951 100644 --- a/src/runtime/virtcontainers/agent.go +++ b/src/runtime/virtcontainers/agent.go @@ -190,4 +190,10 @@ type agent interface { // getAgentMetrics get metrics of agent and guest through agent getAgentMetrics(context.Context, *grpc.GetMetricsRequest) (*grpc.Metrics, error) + + //getGuestVolumeStats get the filesystem stats of a volume specified by the volume mount path on the guest. + getGuestVolumeStats(ctx context.Context, volumeGuestPath string) ([]byte, error) + + // resizeGuestVolume resizes a volume specified by the volume mount path on the guest. + resizeGuestVolume(ctx context.Context, volumeGuestPath string, size uint64) error } diff --git a/src/runtime/virtcontainers/interfaces.go b/src/runtime/virtcontainers/interfaces.go index 85c9d9fe61..bb3935be06 100644 --- a/src/runtime/virtcontainers/interfaces.go +++ b/src/runtime/virtcontainers/interfaces.go @@ -76,6 +76,9 @@ type VCSandbox interface { UpdateRuntimeMetrics() error GetAgentMetrics(ctx context.Context) (string, error) GetAgentURL() (string, error) + + GuestVolumeStats(ctx context.Context, volumePath string) ([]byte, error) + ResizeGuestVolume(ctx context.Context, volumePath string, size uint64) error } // VCContainer is the Container interface diff --git a/src/runtime/virtcontainers/kata_agent.go b/src/runtime/virtcontainers/kata_agent.go index 71781e4ade..6bc8097b7b 100644 --- a/src/runtime/virtcontainers/kata_agent.go +++ b/src/runtime/virtcontainers/kata_agent.go @@ -138,6 +138,8 @@ const ( grpcGetOOMEventRequest = "grpc.GetOOMEventRequest" grpcGetMetricsRequest = "grpc.GetMetricsRequest" grpcAddSwapRequest = "grpc.AddSwapRequest" + grpcVolumeStatsRequest = "grpc.VolumeStatsRequest" + grpcResizeVolumeRequest = "grpc.ResizeVolumeRequest" ) // newKataAgent returns an agent from an agent type. @@ -1952,6 +1954,12 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) { k.reqHandlers[grpcAddSwapRequest] = func(ctx context.Context, req interface{}) (interface{}, error) { return k.client.AgentServiceClient.AddSwap(ctx, req.(*grpc.AddSwapRequest)) } + k.reqHandlers[grpcVolumeStatsRequest] = func(ctx context.Context, req interface{}) (interface{}, error) { + return k.client.AgentServiceClient.GetVolumeStats(ctx, req.(*grpc.VolumeStatsRequest)) + } + k.reqHandlers[grpcResizeVolumeRequest] = func(ctx context.Context, req interface{}) (interface{}, error) { + return k.client.AgentServiceClient.ResizeVolume(ctx, req.(*grpc.ResizeVolumeRequest)) + } } func (k *kataAgent) getReqContext(ctx context.Context, reqName string) (newCtx context.Context, cancel context.CancelFunc) { @@ -2169,3 +2177,22 @@ func (k *kataAgent) getAgentMetrics(ctx context.Context, req *grpc.GetMetricsReq return resp.(*grpc.Metrics), nil } + +func (k *kataAgent) getGuestVolumeStats(ctx context.Context, volumeGuestPath string) ([]byte, error) { + result, err := k.sendReq(ctx, &grpc.VolumeStatsRequest{VolumeGuestPath: volumeGuestPath}) + if err != nil { + return nil, err + } + + buf, err := json.Marshal(result.(*grpc.VolumeStatsResponse)) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (k *kataAgent) resizeGuestVolume(ctx context.Context, volumeGuestPath string, size uint64) error { + _, err := k.sendReq(ctx, &grpc.ResizeVolumeRequest{VolumeGuestPath: volumeGuestPath, Size_: size}) + return err +} diff --git a/src/runtime/virtcontainers/mock_agent.go b/src/runtime/virtcontainers/mock_agent.go index 393597397a..99df3537b4 100644 --- a/src/runtime/virtcontainers/mock_agent.go +++ b/src/runtime/virtcontainers/mock_agent.go @@ -242,3 +242,11 @@ func (n *mockAgent) getOOMEvent(ctx context.Context) (string, error) { func (n *mockAgent) getAgentMetrics(ctx context.Context, req *grpc.GetMetricsRequest) (*grpc.Metrics, error) { return nil, nil } + +func (n *mockAgent) getGuestVolumeStats(ctx context.Context, volumeGuestPath string) ([]byte, error) { + return nil, nil +} + +func (n *mockAgent) resizeGuestVolume(ctx context.Context, volumeGuestPath string, size uint64) error { + return nil +} diff --git a/src/runtime/virtcontainers/pkg/vcmock/sandbox.go b/src/runtime/virtcontainers/pkg/vcmock/sandbox.go index 17fdeb4bf7..b3b5f7a8d1 100644 --- a/src/runtime/virtcontainers/pkg/vcmock/sandbox.go +++ b/src/runtime/virtcontainers/pkg/vcmock/sandbox.go @@ -254,3 +254,10 @@ func (s *Sandbox) GetAgentURL() (string, error) { func (s *Sandbox) GetHypervisorPid() (int, error) { return 0, nil } + +func (s *Sandbox) GuestVolumeStats(ctx context.Context, path string) ([]byte, error) { + return nil, nil +} +func (s *Sandbox) ResizeGuestVolume(ctx context.Context, path string, size uint64) error { + return nil +} diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index 8c72d90cec..9e1ac02b50 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -2257,6 +2257,43 @@ func (s *Sandbox) GetAgentURL() (string, error) { return s.agent.getAgentURL() } +// GuestVolumeStats return the filesystem stat of a given volume in the guest. +func (s *Sandbox) GuestVolumeStats(ctx context.Context, volumePath string) ([]byte, error) { + guestMountPath, err := s.guestMountPath(volumePath) + if err != nil { + return nil, err + } + return s.agent.getGuestVolumeStats(ctx, guestMountPath) +} + +// ResizeGuestVolume resizes a volume in the guest. +func (s *Sandbox) ResizeGuestVolume(ctx context.Context, volumePath string, size uint64) error { + // TODO: https://github.com/kata-containers/kata-containers/issues/3694. + guestMountPath, err := s.guestMountPath(volumePath) + if err != nil { + return err + } + return s.agent.resizeGuestVolume(ctx, guestMountPath, size) +} + +func (s *Sandbox) guestMountPath(volumePath string) (string, error) { + // verify the device even exists + if _, err := os.Stat(volumePath); err != nil { + s.Logger().WithError(err).WithField("volume", volumePath).Error("Cannot get stats for volume that doesn't exist") + return "", err + } + + // verify that we have a mount in this sandbox who's source maps to this + for _, c := range s.containers { + for _, m := range c.mounts { + if volumePath == m.Source { + return m.GuestDeviceMount, nil + } + } + } + return "", fmt.Errorf("mount %s not found in sandbox", volumePath) +} + // getSandboxCPUSet returns the union of each of the sandbox's containers' CPU sets' // cpus and mems as a string in canonical linux CPU/mems list format func (s *Sandbox) getSandboxCPUSet() (string, string, error) {