Skip to content

Commit 5f15ec3

Browse files
balasankarcJoão Pereirajaimem88
committed
Merge branch 'registry-import-command' into 'master'
Add registry-database import command to gitlab-ctl See merge request https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/7265 Merged-by: Balasankar 'Balu' C <[email protected]> Approved-by: Andrew Patterson <[email protected]> Approved-by: Balasankar 'Balu' C <[email protected]> Reviewed-by: João Pereira <[email protected]> Co-authored-by: João Pereira <[email protected]> Co-authored-by: Jaime Martinez <[email protected]>
2 parents acb5a38 + 18e4848 commit 5f15ec3

File tree

5 files changed

+171
-17
lines changed

5 files changed

+171
-17
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
require 'optparse'
2+
3+
module Import
4+
CMD_NAME = 'import'.freeze
5+
SUMMARY_WIDTH = 40
6+
DESC_INDENT = 45
7+
8+
def self.indent(str, len)
9+
str.gsub(/%%/, ' ' * len)
10+
end
11+
12+
USAGE = <<~EOS.freeze
13+
Import filesystem metadata into the database
14+
15+
See documentation at https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/database-import-tool.md
16+
17+
Usage:
18+
gitlab-ctl registry-database import [options]
19+
20+
Options:
21+
-B, --common-blobs Import all blob metadata from common storage
22+
-c, --row-count Count and log number of rows across relevant database tables on (pre)import completion
23+
-d, --dry-run Do not commit changes to the database
24+
-e, --require-empty-database Abort import if the database is not empty
25+
-p, --pre-import Import immutable repository-scoped data to speed up a following import
26+
-r, --all-repositories Import all repository-scoped data
27+
-h, --help Help for import
28+
-1, --step-one pre-import Perform step one of a multi-step import: alias for pre-import
29+
-2, --step-two all-repositories Perform step two of a multi-step import: alias for all-repositories
30+
-3, --step-three common-blobs Perform step three of a multi-step import: alias for common-blobs
31+
EOS
32+
33+
def self.parse_options!(args, parser, options)
34+
return unless args.include? CMD_NAME
35+
36+
loop do
37+
break if args.shift == CMD_NAME
38+
end
39+
40+
parser.on('-h', '--help', 'Usage help') do
41+
parser.set_summary_width(SUMMARY_WIDTH)
42+
Kernel.puts USAGE
43+
Kernel.exit 0
44+
end
45+
46+
parser.on('-B', '--common-blobs', indent('import all blob metadata from common storage', DESC_INDENT)) do
47+
options[:common_blobs] = '--common-blobs'
48+
end
49+
50+
parser.on('-c', '--row-count', indent('count and log number of rows across relevant database tables on (pre)import completion', DESC_INDENT)) do
51+
options[:row_count] = '--row-count'
52+
end
53+
54+
parser.on('-d', '--dry-run', indent('do not commit changes to the database', DESC_INDENT)) do
55+
options[:dry_run] = '--dry-run'
56+
end
57+
58+
parser.on('-e', '--require-empty-database', indent('abort import if the database is not empty', DESC_INDENT)) do
59+
options[:empty] = '--require-empty-database'
60+
end
61+
62+
parser.on('-p', '--pre-import', indent('import immutable repository-scoped data to speed up a following import', DESC_INDENT)) do
63+
options[:pre_import] = '--pre-import'
64+
end
65+
66+
parser.on('-r', '--all-repositories', indent('import all repository-scoped data', DESC_INDENT)) do
67+
options[:all_repositories] = '--all-repositories'
68+
options[:needs_read_only] = true
69+
end
70+
71+
parser.on('-1', '--step-one', indent('perform step one of a multi-step import: alias for pre-import', DESC_INDENT)) do
72+
options[:step_one] = '--step-one'
73+
end
74+
75+
parser.on('-2', '--step-two', indent('perform step two of a multi-step import: alias for all-repositories', DESC_INDENT)) do
76+
options[:step_two] = '--step-two'
77+
options[:needs_read_only] = true
78+
end
79+
80+
parser.on('-3', '--step-three', indent('perform step three of a multi-step import: alias for common-blobs', DESC_INDENT)) do
81+
options[:step_three] = '--step-three'
82+
end
83+
84+
parser.order!(args)
85+
86+
options
87+
end
88+
end

files/gitlab-ctl-commands/lib/registry/migrate.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def self.parse_options!(args, options)
105105
end
106106

107107
def self.populate_subcommands(options)
108-
database_docs_url = 'https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/database-migrations.md?ref_type=heads#administration'
108+
database_docs_url = 'https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/database-migrations.md#administration'
109109

110110
{
111111
'up' => OptionParser.new do |opts|

files/gitlab-ctl-commands/lib/registry/registry_database.rb

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
require 'optparse'
33

44
require_relative './migrate'
5+
require_relative './import'
56

67
module RegistryDatabase
78
EXEC_PATH = '/opt/gitlab/embedded/bin/registry'.freeze
89
CONFIG_PATH = '/var/opt/gitlab/registry/config.yml'.freeze
910

10-
USAGE ||= <<~EOS.freeze
11+
USAGE = <<~EOS.freeze
1112
Usage:
1213
gitlab-ctl registry-database command subcommand [options]
1314
@@ -16,6 +17,7 @@ module RegistryDatabase
1617
1718
COMMANDS:
1819
migrate Manage schema migrations
20+
import Import filesystem metadata into the database
1921
EOS
2022

2123
def self.parse_options!(ctl, args)
@@ -52,7 +54,7 @@ def self.parse_options!(ctl, args)
5254
end
5355

5456
def self.populate_commands(options)
55-
database_docs_url = 'https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/database-migrations.md?ref_type=heads#administration'
57+
database_docs_url = 'https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/database-migrations.md#administration'
5658

5759
{
5860
'migrate' => OptionParser.new do |opts|
@@ -64,6 +66,13 @@ def self.populate_commands(options)
6466
exit 128
6567
end
6668
end,
69+
70+
'import' => OptionParser.new do |parser|
71+
Import.parse_options!(ARGV, parser, options)
72+
rescue OptionParser::ParseError => e
73+
warn "#{e}\n\n#{Import::USAGE}"
74+
exit 128
75+
end,
6776
}
6877
end
6978

@@ -85,23 +94,30 @@ def self.execute(options)
8594

8695
command = set_command(options)
8796

97+
puts "Executing command:\n#{command.join(' ')}\n"
98+
8899
begin
89100
status = Kernel.system(*command)
90101
Kernel.exit!(1) unless status
91102
ensure
92-
start!
103+
start! unless running?
93104
end
94105
end
95106

96107
def self.set_command(options)
97-
command = [EXEC_PATH, "database", options[:command], options[:subcommand]]
98-
108+
command = [EXEC_PATH, "database", options[:command]]
99109
options.delete(:command)
110+
111+
command += [options[:subcommand]] unless options[:subcommand].nil?
100112
options.delete(:subcommand)
113+
101114
needs_stop = options[:needs_stop]
102115
options.delete(:needs_stop)
103116

104-
continue?(needs_stop)
117+
needs_read_only = options[:needs_read_only]
118+
options.delete(:needs_read_only)
119+
120+
continue?(needs_stop, needs_read_only)
105121

106122
command += ["-n", options[:limit]] unless options[:limit].nil?
107123
options.delete(:limit)
@@ -124,6 +140,11 @@ def self.running?
124140
!GitlabCtl::Util.run_command("gitlab-ctl status #{service_name}").error?
125141
end
126142

143+
def self.read_only?
144+
config = YAML.load_file(CONFIG_PATH)
145+
config.dig('storage', 'maintenance', 'readonly', 'enabled') == true
146+
end
147+
127148
def self.start!
128149
puts "Starting service #{service_name}"
129150

@@ -148,17 +169,22 @@ def self.service_name
148169
"registry"
149170
end
150171

151-
def self.continue?(needs_stop)
152-
return unless needs_stop && running?
153-
154-
puts 'WARNING: Migrations cannot be applied while the container registry is running. '\
155-
'Stop the registry before proceeding? (y/n)'.color(:yellow)
172+
def self.continue?(needs_stop, needs_read_only)
173+
if needs_stop && running?
174+
puts 'WARNING: Command cannot run while the container registry is running. ' \
175+
'Stop the registry before proceeding? (y/n)'.color(:yellow)
156176

157-
if $stdin.gets.chomp.casecmp('y').zero?
158-
stop!
159-
else
160-
puts "Exiting..."
161-
exit 1
177+
if $stdin.gets.chomp.casecmp('y').zero?
178+
stop!
179+
else
180+
puts "Exiting..."
181+
exit 1
182+
end
162183
end
184+
185+
return unless running? && needs_read_only && !read_only?
186+
187+
puts 'Command requires the container registry to be in read-only mode. Exiting...'
188+
exit 1
163189
end
164190
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'optparse'
2+
3+
require_relative('../../../../../files/gitlab-ctl-commands/lib/registry/import')
4+
5+
RSpec.describe Import do
6+
describe '.parse_options!' do
7+
before do
8+
allow(Kernel).to receive(:exit) { |code| raise "Kernel.exit(#{code})" }
9+
end
10+
11+
options_data = [
12+
[:common_blobs, 'common-blobs', false],
13+
[:row_count, 'row-count', false],
14+
[:dry_run, 'dry-run', false],
15+
[:empty, 'require-empty-database', false],
16+
[:pre_import, 'pre-import', false],
17+
[:all_repositories, 'all-repositories', true],
18+
[:step_one, 'step-one', false],
19+
[:step_two, 'step-two', true],
20+
[:step_three, 'step-three', false]
21+
]
22+
23+
options_data.each do |option, option_name, read_only|
24+
it "correctly parses the #{option_name} option#{' with read-only mode' if read_only}" do
25+
expected_options = { option => "--#{option_name}" }
26+
expected_options[:needs_read_only] = true if read_only
27+
28+
result = Import.parse_options!(%W[import --#{option_name}], OptionParser.new, {})
29+
expect(result).to eq(expected_options)
30+
end
31+
end
32+
end
33+
end

spec/chef/gitlab-ctl-commands/lib/registry/registry_database_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,12 @@
4242
expect(received).to have_key(:command)
4343
end
4444
end
45+
46+
context 'when command is import' do
47+
let(:command) { 'import' }
48+
49+
it_behaves_like 'unknown option is specified'
50+
it_behaves_like 'parses command options'
51+
end
4552
end
4653
end

0 commit comments

Comments
 (0)