Adds model behavior for RegistryUpstream
What does this MR do and why?
Adds model behavior for RegistryUpstream in Virtual Registry for containers
This is part of a series of MRs for #548783 (closed):
- Add models for Virtual Registry for containers ... (!195984 - merged)
- Add model behavior for Virtual Registry for con... (!199508 - merged)
-
Adds model behavior for RegistryUpstream (!199544 - merged)
👈 We are here - Add cache entry model for Virtual Registry for ... (!199567 - merged)
References
- Container image virtual registry: database models (#548783 - closed)
- Add models for Virtual Registry for containers ... (!195984 - merged)
- Add model behavior for Virtual Registry for con... (!199508 - merged)
Screenshots or screen recordings
NA
Database Review
RegistryUpstream.sync_higher_positions
We can have 5
docker registries max.
Each registry can be connected to 5
upstreams max.
So the worst case scenario here would be max 25
(5x5)
These are empty tables in production. Here's the EXPLAIN ANALYZE output from GDK.
SQL
EXPLAIN UPDATE virtual_registries_container_registry_upstreams
SET
position = position - 1
WHERE
virtual_registries_container_registry_upstreams.id IN (
SELECT
virtual_registries_container_registry_upstreams.id
FROM
virtual_registries_container_registry_upstreams
JOIN (
SELECT
virtual_registries_container_registry_upstreams.registry_id,
virtual_registries_container_registry_upstreams.position
FROM
virtual_registries_container_registry_upstreams
WHERE
virtual_registries_container_registry_upstreams.registry_id = 5
ORDER BY
virtual_registries_container_registry_upstreams.position ASC
) AS subquery ON virtual_registries_container_registry_upstreams.registry_id = subquery.registry_id
WHERE
virtual_registries_container_registry_upstreams.position > subquery.position
);
Query plan
Update on virtual_registries_container_registry_upstreams (cost=15.53..17.14 rows=0 width=0)
-> Nested Loop (cost=15.53..17.14 rows=9 width=48)
-> HashAggregate (cost=15.37..15.46 rows=9 width=48)
Group Key: virtual_registries_container_registry_upstreams_1.id
-> Nested Loop (cost=0.30..15.35 rows=9 width=48)
-> Subquery Scan on subquery (cost=0.15..5.29 rows=5 width=44)
-> Index Only Scan using constraint_vreg_container_reg_upst_on_unique_reg_pos on virtual_registries_container_registry_upstreams virtual_registries_container_registry_upstreams_2 (cost=0.15..5.24 rows=5 width=10)
Index Cond: (registry_id = 5)
-> Index Scan using constraint_vreg_container_reg_upst_on_unique_reg_pos on virtual_registries_container_registry_upstreams virtual_registries_container_registry_upstreams_1 (cost=0.15..1.99 rows=2 width=24)
Index Cond: ((registry_id = subquery.registry_id) AND ("position" > subquery."position"))
-> Index Scan using virtual_registries_container_registry_upstreams_pkey on virtual_registries_container_registry_upstreams (cost=0.15..0.18 rows=1 width=16)
Index Cond: (id = virtual_registries_container_registry_upstreams_1.id)
RegistryUpstream#sync_higher_positions
We can have 5
docker registries max.
Each registry can be connected to 5
upstreams max.
So the worst case scenario here would be max 25
(5x5)
These are empty tables in production. Here's the EXPLAIN ANALYZE output from GDK.
SQL
EXPLAIN
UPDATE virtual_registries_container_registry_upstreams
SET
position = position - 1
WHERE
virtual_registries_container_registry_upstreams.registry_id = 5 AND
virtual_registries_container_registry_upstreams.position >= 5;
Query plan
Update on virtual_registries_container_registry_upstreams (cost=0.15..3.20 rows=0 width=0)
-> Index Scan using constraint_vreg_container_reg_upst_on_unique_reg_pos on virtual_registries_container_registry_upstreams (cost=0.15..3.20 rows=2 width=8)
Index Cond: ((registry_id = 5) AND ("position" >= 5))
RegistryUpstream#update_position
We can have 5
docker registries max.
Each registry can be connected to 5
upstreams max.
So the worst case scenario here would be max 25
(5x5)
These are empty tables in production. Here's the EXPLAIN ANALYZE output from GDK.
SQL
EXPLAIN
UPDATE virtual_registries_container_registry_upstreams
SET
position = CASE
WHEN virtual_registries_container_registry_upstreams.id = 5 THEN 1
WHEN virtual_registries_container_registry_upstreams.position = 1 THEN virtual_registries_container_registry_upstreams.position + 1
ELSE virtual_registries_container_registry_upstreams.position
END
WHERE
virtual_registries_container_registry_upstreams.registry_id = 5;
Query plan
Update on virtual_registries_container_registry_upstreams (cost=0.15..5.30 rows=0 width=0)
-> Index Scan using constraint_vreg_container_reg_upst_on_unique_reg_pos on virtual_registries_container_registry_upstreams (cost=0.15..5.30 rows=5 width=8)
Index Cond: (registry_id = 5)
How to set up and validate locally
The only way to test is from the Rails console
1️⃣ Registry
model
# get a root group
root_group = Group.first
# make sure that it's a root one
root_group.root?
=> true
# create a subgroup
subgroup = FactoryBot.create(:group, parent: root_group, name: 'test-subgroup')
# alternative to previous step, if you already created test-subgroup
subgroup = Namespace.where(parent: root_group, name: 'test-subgroup').first
# The registry object is the entry point of the feature and can only be linked with a root group.
# Let's try to create a registry on the subgroup:
r = ::VirtualRegistries::Container::Registry.create!(group: subgroup, name: subgroup.name)
ActiveRecord::RecordInvalid: Validation failed: Group must be a top level Group
# Create a registry on the root group:
r = ::VirtualRegistries::Container::Registry.create!(group: root_group, name: root_group.name)
=> #<VirtualRegistries::Container::Registry:0x00000001200f5f20 id: ....>
# Registry name should be unique within a group:
::VirtualRegistries::Container::Registry.create!(group: root_group, name: root_group.name)
ActiveRecord::RecordInvalid: Validation failed: Group has already been taken
2️⃣ Upstream
model
# Given that the association with the registry is handled in a join table, an upstream can be created without pointing to a registry
# Let's check some of its validations
# name and credentials should be set
my_google_registry_url = "https://us-central1-docker.pkg.dev/my-project-id/my-repo/my-app:latest"
u = ::VirtualRegistries::Container::Upstream.create!(group: root_group, url: my_google_registry_url)
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank, Credentials must be a valid json schema
u_name = 'my-project-registry'
username = 'batman'
password = 'askalfred'
u = ::VirtualRegistries::Container::Upstream.create!(group: root_group, name: u_name, username: username, password: password, url: my_google_registry_url)
# Let's check some of its validations
# url should be correctly formatted
u.update!(url: "test")
ActiveRecord::RecordInvalid: Validation failed: Url is blocked: Only allowed schemes are http, https
u.reload
# credentials should both be set
u.update!(username: '', password: 'newpassword')
ActiveRecord::RecordInvalid: Validation failed: Username can't be blank
u.update!(username: 'newbatman', password: 'newpassword')
=> true
3️⃣ RegistryUpstream
model
ru = ::VirtualRegistries::Container::RegistryUpstream.create!(group: root_group, registry: r, upstream: u)
=> #<VirtualRegistries::Container::RegistryUpstream:0x000000011cdd8340
# We don't allow multiple upstreams for the same registry
::VirtualRegistries::Container::RegistryUpstream.create!(group: root_group, registry: r, upstream: u)
ActiveRecord::RecordInvalid: Validation failed: Upstream has already been taken
r.upstreams.first
=> #<VirtualRegistries::Container::Upstream:0x0000000169731b98
u.registries.first
=> #<VirtualRegistries::Container::Registry:0x000000016967a650
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #548783 (closed)