Commit 81a54f29 authored by nnelson's avatar nnelson Committed by Stan Hu

Support retrieval of disk statistics from Gitaly

Add a rudimentary client implementation for the new gitaly
disk_statistics grpc.

Add unit tests.

New gitaly server methods include disk_used and
disk_available.  This commit adds unit testing
for those methods.

Add default server response on error

When the remote service is unavailable, times out,
or otherwise causes a service call failure, return
a default response with trivial values set to its
fields.
parent 9c5e879b
---
title: "Support retrieval of disk statistics from Gitaly"
merge_request: 22226
author: Nels Nelson
type: added
......@@ -53,6 +53,20 @@ module Gitaly
storage_status&.fs_type
end
def disk_used
disk_statistics_storage_status&.used
end
def disk_available
disk_statistics_storage_status&.available
end
# Simple convenience method for when obtaining both used and available
# statistics at once is preferred.
def disk_stats
disk_statistics_storage_status
end
def address
Gitlab::GitalyClient.address(@storage)
rescue RuntimeError => e
......@@ -65,6 +79,10 @@ module Gitaly
@storage_status ||= info.storage_statuses.find { |s| s.storage_name == storage }
end
def disk_statistics_storage_status
@disk_statistics_storage_status ||= disk_statistics.storage_statuses.find { |s| s.storage_name == storage }
end
def matches_sha?
match = server_version.match(SHA_VERSION_REGEX)
return false unless match
......@@ -76,7 +94,19 @@ module Gitaly
@info ||=
begin
Gitlab::GitalyClient::ServerService.new(@storage).info
rescue GRPC::Unavailable, GRPC::DeadlineExceeded
rescue GRPC::Unavailable, GRPC::DeadlineExceeded => ex
Gitlab::ErrorTracking.track_exception(ex)
# This will show the server as being out of date
Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: [])
end
end
def disk_statistics
@disk_statistics ||=
begin
Gitlab::GitalyClient::ServerService.new(@storage).disk_statistics
rescue GRPC::Unavailable, GRPC::DeadlineExceeded => ex
Gitlab::ErrorTracking.track_exception(ex)
# This will show the server as being out of date
Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: [])
end
......
......@@ -432,10 +432,7 @@ module Gitlab
end
def self.filesystem_id(storage)
response = Gitlab::GitalyClient::ServerService.new(storage).info
storage_status = response.storage_statuses.find { |status| status.storage_name == storage }
storage_status&.filesystem_id
Gitlab::GitalyClient::ServerService.new(storage).storage_info&.filesystem_id
end
def self.filesystem_id_from_disk(storage)
......@@ -446,6 +443,14 @@ module Gitlab
nil
end
def self.filesystem_disk_available(storage)
Gitlab::GitalyClient::ServerService.new(storage).storage_disk_statistics&.available
end
def self.filesystem_disk_used(storage)
Gitlab::GitalyClient::ServerService.new(storage).storage_disk_statistics&.used
end
def self.timeout(timeout_name)
Gitlab::CurrentSettings.current_application_settings[timeout_name]
end
......
......@@ -13,6 +13,24 @@ module Gitlab
def info
GitalyClient.call(@storage, :server_service, :server_info, Gitaly::ServerInfoRequest.new, timeout: GitalyClient.fast_timeout)
end
def disk_statistics
GitalyClient.call(@storage, :server_service, :disk_statistics, Gitaly::DiskStatisticsRequest.new, timeout: GitalyClient.fast_timeout)
end
def storage_info
storage_specific(info)
end
def storage_disk_statistics
storage_specific(disk_statistics)
end
private
def storage_specific(response)
response.storage_statuses.find { |status| status.storage_name == @storage }
end
end
end
end
......@@ -66,6 +66,53 @@ describe Gitaly::Server do
end
end
context "when examining disk statistics for a given server" do
let(:disk_available) { 42 }
let(:disk_used) { 42 }
let(:storage_status) { double('storage_status') }
before do
allow(storage_status).to receive(:storage_name).and_return('default')
allow(storage_status).to receive(:available).and_return(disk_available)
allow(storage_status).to receive(:used).and_return(disk_used)
response = double("response")
allow(response).to receive(:storage_statuses).and_return([storage_status])
allow_next_instance_of(Gitlab::GitalyClient::ServerService) do |instance|
allow(instance).to receive(:disk_statistics).and_return(response)
end
end
describe '#disk_available' do
subject { server.disk_available }
it { is_expected.to be_present }
it "returns disk available for the storage of the instantiated server" do
is_expected.to eq(disk_available)
end
end
describe '#disk_used' do
subject { server.disk_used }
it { is_expected.to be_present }
it "returns disk used for the storage of the instantiated server" do
is_expected.to eq(disk_used)
end
end
describe '#disk_stats' do
subject { server.disk_stats }
it { is_expected.to be_present }
it "returns the storage of the instantiated server" do
is_expected.to eq(storage_status)
end
end
end
describe '#expected_version?' do
using RSpec::Parameterized::TableSyntax
......
......@@ -52,7 +52,7 @@ describe Gitlab::GitalyClient do
end
describe '.filesystem_id' do
it 'returns an empty string when the storage is not found in the response' do
it 'returns an empty string when the relevant storage status is not found in the response' do
response = double("response")
allow(response).to receive(:storage_statuses).and_return([])
allow_next_instance_of(Gitlab::GitalyClient::ServerService) do |instance|
......@@ -63,6 +63,63 @@ describe Gitlab::GitalyClient do
end
end
context 'when the relevant storage status is not found' do
before do
response = double('response')
allow(response).to receive(:storage_statuses).and_return([])
allow_next_instance_of(Gitlab::GitalyClient::ServerService) do |instance|
allow(instance).to receive(:disk_statistics).and_return(response)
expect(instance).to receive(:storage_disk_statistics)
end
end
describe '.filesystem_disk_available' do
it 'returns nil when the relevant storage status is not found in the response' do
expect(described_class.filesystem_disk_available('default')).to eq(nil)
end
end
describe '.filesystem_disk_used' do
it 'returns nil when the relevant storage status is not found in the response' do
expect(described_class.filesystem_disk_used('default')).to eq(nil)
end
end
end
context 'when the relevant storage status is found' do
let(:disk_available) { 42 }
let(:disk_used) { 42 }
let(:storage_status) { double('storage_status') }
before do
allow(storage_status).to receive(:storage_name).and_return('default')
allow(storage_status).to receive(:used).and_return(disk_used)
allow(storage_status).to receive(:available).and_return(disk_available)
response = double('response')
allow(response).to receive(:storage_statuses).and_return([storage_status])
allow_next_instance_of(Gitlab::GitalyClient::ServerService) do |instance|
allow(instance).to receive(:disk_statistics).and_return(response)
end
expect_next_instance_of(Gitlab::GitalyClient::ServerService) do |instance|
expect(instance).to receive(:storage_disk_statistics).and_return(storage_status)
end
end
describe '.filesystem_disk_available' do
it 'returns disk available when the relevant storage status is found in the response' do
expect(storage_status).to receive(:available)
expect(described_class.filesystem_disk_available('default')).to eq(disk_available)
end
end
describe '.filesystem_disk_used' do
it 'returns disk used when the relevant storage status is found in the response' do
expect(storage_status).to receive(:used)
expect(described_class.filesystem_disk_used('default')).to eq(disk_used)
end
end
end
describe '.stub_class' do
it 'returns the gRPC health check stub' do
expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment