feat(sql): Add history tables for hosts
This adds history tables for `static_host` and `host_plugin_host`. This also adds a base table for the host history tables. This also adds a new test to the history table test suite. The new test verifies the contents of each history table against the contents of their operational table.
This commit is contained in:
1 parent
b97dc07bb0
commit
37c6b8e540
5 files changed
+272
-7
No files matched your search
@@ -0,0 +1,130 @@
|
||||
-- Copyright (c) HashiCorp, Inc.
|
||||
-- SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
begin;
|
||||
|
||||
create table host_history_base (
|
||||
history_id wt_url_safe_id primary key
|
||||
);
|
||||
comment on table host_history_base is
|
||||
'host_history_base is a base history table '
|
||||
'for host history tables.';
|
||||
|
||||
create function insert_host_history_subtype() returns trigger
|
||||
as $$
|
||||
begin
|
||||
insert into host_history_base
|
||||
(history_id)
|
||||
values
|
||||
(new.history_id);
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function insert_host_history_subtype is
|
||||
'insert_host_history_subtype is a before insert trigger '
|
||||
'function for subtypes of host_history_base.';
|
||||
|
||||
create function delete_host_history_subtype() returns trigger
|
||||
as $$
|
||||
begin
|
||||
delete
|
||||
from host_history_base
|
||||
where history_id = old.history_id;
|
||||
return null; -- result is ignored since this is an after trigger
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function delete_host_history_subtype is
|
||||
'delete_host_history_subtype() is an after delete trigger '
|
||||
'function for subtypes of host_history_base.';
|
||||
|
||||
create table no_host_history (
|
||||
history_id wt_url_safe_id primary key
|
||||
constraint host_history_base_fkey
|
||||
references host_history_base (history_id)
|
||||
on delete restrict
|
||||
on update restrict
|
||||
);
|
||||
comment on table no_host_history is
|
||||
'no_host_history is a table with one row to represent '
|
||||
'the case of a target with a direct address associated to it.';
|
||||
|
||||
insert into host_history_base values ('_______none');
|
||||
insert into no_host_history values ('_______none');
|
||||
|
||||
create trigger immutable_table before insert or update or delete on no_host_history
|
||||
for each row execute procedure immutable_table();
|
||||
|
||||
create table static_host_hst (
|
||||
public_id wt_public_id not null,
|
||||
name text null,
|
||||
description text null,
|
||||
catalog_id wt_public_id not null,
|
||||
address text not null,
|
||||
history_id wt_url_safe_id default wt_url_safe_id() primary key
|
||||
constraint host_history_base_fkey
|
||||
references host_history_base (history_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
valid_range tstzrange not null default tstzrange(current_timestamp, null),
|
||||
constraint static_host_hst_valid_range_excl
|
||||
exclude using gist (public_id with =, valid_range with &&)
|
||||
);
|
||||
comment on table static_host_hst is
|
||||
'static_host_hst is a history table where each row contains the values from a row '
|
||||
'in the static_host table during the time range in the valid_range column.';
|
||||
|
||||
create trigger insert_host_history_subtype before insert on static_host_hst
|
||||
for each row execute function insert_host_history_subtype();
|
||||
create trigger delete_host_history_subtype after delete on static_host_hst
|
||||
for each row execute function delete_host_history_subtype();
|
||||
|
||||
create trigger hst_on_insert after insert on static_host
|
||||
for each row execute function hst_on_insert();
|
||||
create trigger hst_on_update after update on static_host
|
||||
for each row execute function hst_on_update();
|
||||
create trigger hst_on_delete after delete on static_host
|
||||
for each row execute function hst_on_delete();
|
||||
|
||||
insert into static_host_hst
|
||||
(public_id, name, description, catalog_id, address)
|
||||
select public_id, name, description, catalog_id, address
|
||||
from static_host;
|
||||
|
||||
create table host_plugin_host_hst (
|
||||
public_id wt_public_id not null,
|
||||
name wt_name null,
|
||||
description text null,
|
||||
catalog_id wt_public_id not null,
|
||||
external_id text not null,
|
||||
external_name text null,
|
||||
history_id wt_url_safe_id default wt_url_safe_id() primary key
|
||||
constraint host_history_base_fkey
|
||||
references host_history_base (history_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
valid_range tstzrange not null default tstzrange(current_timestamp, null),
|
||||
constraint host_plugin_host_hst_valid_range_excl
|
||||
exclude using gist (public_id with =, valid_range with &&)
|
||||
);
|
||||
comment on table host_plugin_host_hst is
|
||||
'host_plugin_host_hst is a history table where each row contains the values from a row '
|
||||
'in the host_plugin_host table during the time range in the valid_range column.';
|
||||
|
||||
create trigger insert_host_history_subtype before insert on host_plugin_host_hst
|
||||
for each row execute function insert_host_history_subtype();
|
||||
create trigger delete_host_history_subtype after delete on host_plugin_host_hst
|
||||
for each row execute function delete_host_history_subtype();
|
||||
|
||||
create trigger hst_on_insert after insert on host_plugin_host
|
||||
for each row execute function hst_on_insert();
|
||||
create trigger hst_on_update after update on host_plugin_host
|
||||
for each row execute function hst_on_update();
|
||||
create trigger hst_on_delete after delete on host_plugin_host
|
||||
for each row execute function hst_on_delete();
|
||||
|
||||
insert into host_plugin_host_hst
|
||||
(public_id, name, description, catalog_id, external_id, external_name)
|
||||
select public_id, name, description, catalog_id, external_id, external_name
|
||||
from host_plugin_host;
|
||||
|
||||
commit;
|
||||
@@ -295,6 +295,57 @@ begin;
|
||||
('p____bcolors', 'plg_____chost', 'c___cb-plghcl', 'Blue Color Plugin Catalog', ''),
|
||||
('p____rcolors', 'plg_____chost', 'c___cr-plghcl', 'Red Color Plugin Catalog', '');
|
||||
|
||||
insert into host_plugin_host
|
||||
(catalog_id, public_id, external_id)
|
||||
values
|
||||
('c___cb-plghcl', 'h_____cb__01-plgh', '1 blue color'),
|
||||
('c___cb-plghcl', 'h_____cb__02-plgh', '2 blue color'),
|
||||
('c___cb-plghcl', 'h_____cb__03-plgh', '3 blue color'),
|
||||
|
||||
('c___cr-plghcl', 'h_____cr__01-plgh', '1 red color'),
|
||||
('c___cr-plghcl', 'h_____cr__02-plgh', '2 red color'),
|
||||
('c___cr-plghcl', 'h_____cr__03-plgh', '3 red color');
|
||||
|
||||
insert into host_dns_name
|
||||
(host_id, name)
|
||||
values
|
||||
('h_____cb__01-plgh', '1.blue.color'),
|
||||
('h_____cb__02-plgh', '2.blue.color'),
|
||||
('h_____cb__03-plgh', '3.blue.color'),
|
||||
|
||||
('h_____cr__01-plgh', '1.red.color'),
|
||||
('h_____cr__02-plgh', '2.red.color'),
|
||||
('h_____cr__03-plgh', '3.red.color');
|
||||
|
||||
insert into host_ip_address
|
||||
(host_id, address)
|
||||
values
|
||||
('h_____cb__01-plgh', '1.1.1.1'),
|
||||
('h_____cb__02-plgh', 'fe80::2222:2222:2222:2222'),
|
||||
-- host 3 only has a dns name so the set of addresses are the same
|
||||
-- between the static and plugin based host
|
||||
|
||||
('h_____cr__01-plgh', '11.11.11.11'),
|
||||
('h_____cr__02-plgh', '2001:4860:4860::2222'),
|
||||
('h_____cr__03-plgh', '33.33.33.33');
|
||||
|
||||
insert into host_plugin_set
|
||||
(catalog_id, public_id, name, attributes, need_sync)
|
||||
values
|
||||
('c___cb-plghcl', 's___1cb-plghs', 'Blue Color Plugin Set 1', '', false),
|
||||
('c___cb-plghcl', 's___2cb-plghs', 'Blue Color Plugin Set 2', '', false),
|
||||
('c___cr-plghcl', 's___1cr-plghs', 'Red Color Plugin Set 1', '', false),
|
||||
('c___cr-plghcl', 's___2cr-plghs', 'Red Color Plugin Set 2', '', false);
|
||||
|
||||
insert
|
||||
into host_plugin_set_member
|
||||
( host_id, set_id, catalog_id)
|
||||
select h.public_id, s.public_id, s.catalog_id
|
||||
from host_plugin_host as h,
|
||||
host_plugin_set as s
|
||||
where h.catalog_id = s.catalog_id
|
||||
and h.external_id like '%color';
|
||||
|
||||
insert into target_tcp
|
||||
(project_id, public_id, name)
|
||||
values
|
||||
|
||||
@@ -334,7 +334,8 @@ begin;
|
||||
select h.public_id, s.public_id, s.catalog_id
|
||||
from host_plugin_host as h,
|
||||
host_plugin_set as s
|
||||
where h.catalog_id = s.catalog_id;
|
||||
where h.catalog_id = s.catalog_id
|
||||
and h.external_id like '%widget';
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
|
||||
begin;
|
||||
|
||||
create function get_columns(history_table_name name) returns setof text
|
||||
as $$
|
||||
begin
|
||||
return query
|
||||
select quote_ident(attname)
|
||||
from pg_attribute
|
||||
where attrelid = op_table(history_table_name)::regclass
|
||||
and not attisdropped -- no dropped (dead) columns
|
||||
and attnum > 0 -- no system columns
|
||||
intersect
|
||||
select quote_ident(attname)
|
||||
from pg_attribute
|
||||
where attrelid = history_table_name::regclass
|
||||
and not attisdropped -- no dropped (dead) columns
|
||||
and attnum > 0; -- no system columns
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create function get_history_tables() returns setof name
|
||||
as $$
|
||||
select c.relname
|
||||
@@ -44,25 +62,52 @@ begin;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create function migrations_have_run(history_table_name name) returns text
|
||||
create function has_expected_row_count(history_table_name name) returns text
|
||||
as $$
|
||||
declare
|
||||
result text;
|
||||
begin
|
||||
execute format('select is(count(opt.*), count(hst.*)) '
|
||||
'from %I opt, %I hst', op_table(history_table_name), history_table_name)
|
||||
execute format('select results_eq( '
|
||||
' ''select count(*) from %I'', '
|
||||
' ''select count(*) from %I'') ',
|
||||
op_table(history_table_name), history_table_name)
|
||||
into result;
|
||||
return result;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create function has_expected_content(history_table_name name) returns text
|
||||
as $$
|
||||
declare
|
||||
_cols text;
|
||||
_q1 text;
|
||||
_q2 text;
|
||||
begin
|
||||
select into _cols
|
||||
string_agg(quote_ident(get_columns), ', ')
|
||||
from get_columns(history_table_name);
|
||||
select into _q1 format('select %s from %s', _cols, history_table_name);
|
||||
select into _q2 format('select %s from %s', _cols, op_table(history_table_name));
|
||||
return results_eq(_q1, _q2);
|
||||
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create function has_expected_data(history_table_name name) returns text
|
||||
as $$
|
||||
select * from collect_tap(
|
||||
has_expected_row_count(history_table_name),
|
||||
has_expected_content(history_table_name)
|
||||
);
|
||||
$$ language sql;
|
||||
|
||||
-- tests the tables exist and follow the required naming pattern
|
||||
create function has_correct_tables(history_table_name name) returns text
|
||||
as $$
|
||||
select * from collect_tap(
|
||||
has_table(history_table_name),
|
||||
has_operational_table(history_table_name),
|
||||
migrations_have_run(history_table_name)
|
||||
has_expected_data(history_table_name)
|
||||
);
|
||||
$$ language sql;
|
||||
|
||||
@@ -144,10 +189,10 @@ begin;
|
||||
);
|
||||
$$ language sql;
|
||||
|
||||
-- 27 tests for each history table
|
||||
-- 28 tests for each history table
|
||||
select plan(a.table_count::integer)
|
||||
from (
|
||||
select 27 * count(*) as table_count
|
||||
select 28 * count(*) as table_count
|
||||
from get_history_tables()
|
||||
) as a;
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
-- Copyright (c) HashiCorp, Inc.
|
||||
-- SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
begin;
|
||||
|
||||
select plan(15);
|
||||
|
||||
-- Verify the trigger functions exist and are declared properly
|
||||
select has_function('insert_host_history_subtype');
|
||||
select volatility_is('insert_host_history_subtype', 'volatile');
|
||||
select isnt_strict('insert_host_history_subtype');
|
||||
|
||||
select has_function('delete_host_history_subtype');
|
||||
select volatility_is('delete_host_history_subtype', 'volatile');
|
||||
select isnt_strict('delete_host_history_subtype');
|
||||
|
||||
select has_trigger('static_host_hst', 'insert_host_history_subtype');
|
||||
select has_trigger('static_host_hst', 'delete_host_history_subtype');
|
||||
select fk_ok('static_host_hst', 'history_id', 'host_history_base' , 'history_id');
|
||||
|
||||
select has_trigger('host_plugin_host_hst', 'insert_host_history_subtype');
|
||||
select has_trigger('host_plugin_host_hst', 'delete_host_history_subtype');
|
||||
select fk_ok('host_plugin_host_hst', 'history_id', 'host_history_base' , 'history_id');
|
||||
|
||||
select is(count(*), 1::bigint) from no_host_history;
|
||||
select fk_ok('no_host_history', 'history_id', 'host_history_base' , 'history_id');
|
||||
|
||||
select results_eq(
|
||||
'select '
|
||||
'(select count(*) from static_host_hst) + '
|
||||
'(select count(*) from host_plugin_host_hst) + '
|
||||
'(select count(*) from no_host_history)',
|
||||
'select count(*) from host_history_base'
|
||||
);
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
|
||||
Reference in new issue
Block a user