Add worker tagging (#862)
This allows workers to have tags assigned to them, which can then be filtered to control which targets they are allowed to serve.
This commit is contained in:
1 parent
595a86508e
commit
717a3b52ee
54 files changed
+2150
-666
No files matched your search
@@ -95,6 +95,148 @@ returning id;
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomain_TagPairs(t *testing.T) {
|
||||
const (
|
||||
createTable = `
|
||||
create table if not exists test_table (
|
||||
pair wt_tagpair primary key
|
||||
);
|
||||
`
|
||||
insert = `
|
||||
insert into test_table
|
||||
values ($1);
|
||||
`
|
||||
)
|
||||
|
||||
conn, _ := TestSetup(t, "postgres")
|
||||
db := conn.DB()
|
||||
|
||||
if _, err := db.Exec(createTable); err != nil {
|
||||
t.Fatalf("query: \n%s\n error: %s", createTable, err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
value string
|
||||
fail bool
|
||||
}{
|
||||
{
|
||||
" ",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"00000009",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ABC123",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"092h3oiuansdfh98wh3piornasiopudhfp98aw384rhfaouisdhnfios",
|
||||
false,
|
||||
},
|
||||
{
|
||||
strings.Repeat("1234567890", 51),
|
||||
false,
|
||||
},
|
||||
{
|
||||
strings.Repeat("1234567890", 52),
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.value, func(t *testing.T) {
|
||||
// t.Logf("insert value: %q", tt.value)
|
||||
_, err := db.Query(insert, tt.value)
|
||||
switch {
|
||||
case err == nil && tt.fail:
|
||||
t.Errorf("want error, got no error for inserting value: %s", tt.value)
|
||||
case err == nil && !tt.fail:
|
||||
// All good
|
||||
case err != nil && tt.fail:
|
||||
// All good
|
||||
default:
|
||||
t.Errorf("expected no error, got error: %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("null", func(t *testing.T) {
|
||||
_, err := db.Query("insert into test_table values (null);")
|
||||
assert.Contains(t, err.Error(), "violates check constraint")
|
||||
})
|
||||
}
|
||||
|
||||
func TestDomain_Bexprfilter(t *testing.T) {
|
||||
const (
|
||||
createTable = `
|
||||
create table if not exists test_table (
|
||||
filter wt_bexprfilter
|
||||
);
|
||||
`
|
||||
insert = `
|
||||
insert into test_table
|
||||
values ($1);
|
||||
`
|
||||
)
|
||||
|
||||
conn, _ := TestSetup(t, "postgres")
|
||||
db := conn.DB()
|
||||
|
||||
if _, err := db.Exec(createTable); err != nil {
|
||||
t.Fatalf("query: \n%s\n error: %s", createTable, err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
value string
|
||||
fail bool
|
||||
}{
|
||||
{
|
||||
" ",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"00000009",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ABC123",
|
||||
false,
|
||||
},
|
||||
{
|
||||
`"/foo/bar" in "/values"`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
strings.Repeat("1234567890", 204),
|
||||
false,
|
||||
},
|
||||
{
|
||||
strings.Repeat("1234567890", 205),
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.value, func(t *testing.T) {
|
||||
// t.Logf("insert value: %q", tt.value)
|
||||
_, err := db.Query(insert, tt.value)
|
||||
switch {
|
||||
case err == nil && tt.fail:
|
||||
t.Errorf("want error, got no error for inserting value: %s", tt.value)
|
||||
case err == nil && !tt.fail:
|
||||
// All good
|
||||
case err != nil && tt.fail:
|
||||
// All good
|
||||
default:
|
||||
t.Errorf("expected no error, got error: %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("null", func(t *testing.T) {
|
||||
_, err := db.Query("insert into test_table values (null);")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDomain_Timestamp(t *testing.T) {
|
||||
const (
|
||||
createTable = `
|
||||
|
||||
@@ -1054,9 +1054,8 @@ func filterPaths(paths []string) []string {
|
||||
}
|
||||
|
||||
func setFieldsToNil(i interface{}, fieldNames []string) {
|
||||
if err := Clear(i, fieldNames, 2); err != nil {
|
||||
// do nothing
|
||||
}
|
||||
// Note: error cases are not handled
|
||||
_ = Clear(i, fieldNames, 2)
|
||||
}
|
||||
|
||||
func isNil(i interface{}) bool {
|
||||
|
||||
@@ -4,5 +4,6 @@ THIS_FILE := $(lastword $(MAKEFILE_LIST))
|
||||
migrations:
|
||||
go run .
|
||||
goimports -w ${GEN_BASEPATH}/internal/db/schema
|
||||
gofumpt -w ${GEN_BASEPATH}/internal/db/schema
|
||||
|
||||
.PHONY: migrations
|
||||
@@ -154,6 +154,7 @@ before insert on target_tcp
|
||||
|
||||
|
||||
-- target_all_subtypes is a union of all target subtypes
|
||||
-- NOTE: this is replaced in 100 to add worker_filter
|
||||
create view target_all_subtypes
|
||||
as
|
||||
select
|
||||
|
||||
@@ -158,6 +158,7 @@ begin;
|
||||
endpoint text -- not part of the warehouse, used to send info to the worker
|
||||
);
|
||||
|
||||
-- Replaced in 100 to add worker_filter
|
||||
create trigger
|
||||
immutable_columns
|
||||
before
|
||||
@@ -453,6 +454,7 @@ begin;
|
||||
create trigger insert_session_state before insert on session_state
|
||||
for each row execute procedure insert_session_state();
|
||||
|
||||
-- Replaced in 100 to add worker_filter
|
||||
create view session_with_state as
|
||||
select
|
||||
s.public_id,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
begin;
|
||||
|
||||
drop domain wt_bexprfilter;
|
||||
|
||||
drop table server_tag;
|
||||
drop domain wt_tagpair;
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,123 @@
|
||||
begin;
|
||||
|
||||
-- This series of expressions fixes the primary key on the server table
|
||||
alter table session
|
||||
drop constraint session_server_id_server_type_fkey;
|
||||
alter table server
|
||||
drop constraint server_pkey;
|
||||
alter table server
|
||||
drop column name;
|
||||
alter table server
|
||||
add primary key (private_id);
|
||||
alter table server
|
||||
add constraint server_id_must_not_be_empty
|
||||
check(length(trim(private_id)) > 0);
|
||||
alter table session
|
||||
add constraint session_server_id_fkey
|
||||
foreign key (server_id)
|
||||
references server(private_id)
|
||||
on delete set null
|
||||
on update cascade;
|
||||
|
||||
create domain wt_bexprfilter as text
|
||||
check(
|
||||
value is null
|
||||
or
|
||||
(
|
||||
length(trim(value)) > 0
|
||||
and
|
||||
length(trim(value)) <= 2048
|
||||
)
|
||||
);
|
||||
comment on domain wt_bexprfilter is
|
||||
'Text field with constraints for go-bexpr filters';
|
||||
|
||||
-- Add the worker filter to the target_tcp table and session table
|
||||
alter table target_tcp
|
||||
add column worker_filter wt_bexprfilter;
|
||||
alter table session
|
||||
add column worker_filter wt_bexprfilter;
|
||||
|
||||
-- Replace the immutable columns trigger from 50 to add worker_filter
|
||||
drop trigger immutable_columns on session;
|
||||
create trigger immutable_columns
|
||||
before update on session
|
||||
for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint', 'worker_filter');
|
||||
|
||||
-- Replaces the view created in 41 to include worker_filter
|
||||
drop view target_all_subtypes;
|
||||
create view target_all_subtypes
|
||||
as
|
||||
select
|
||||
public_id,
|
||||
scope_id,
|
||||
name,
|
||||
description,
|
||||
default_port,
|
||||
session_max_seconds,
|
||||
session_connection_limit,
|
||||
version,
|
||||
create_time,
|
||||
update_time,
|
||||
worker_filter,
|
||||
'tcp' as type
|
||||
from target_tcp;
|
||||
|
||||
-- Replaces the view created in 50 to include worker_filter
|
||||
drop view session_with_state;
|
||||
create view session_with_state as
|
||||
select
|
||||
s.public_id,
|
||||
s.user_id,
|
||||
s.host_id,
|
||||
s.server_id,
|
||||
s.server_type,
|
||||
s.target_id,
|
||||
s.host_set_id,
|
||||
s.auth_token_id,
|
||||
s.scope_id,
|
||||
s.certificate,
|
||||
s.expiration_time,
|
||||
s.connection_limit,
|
||||
s.tofu_token,
|
||||
s.key_id,
|
||||
s.termination_reason,
|
||||
s.version,
|
||||
s.create_time,
|
||||
s.update_time,
|
||||
s.endpoint,
|
||||
s.worker_filter,
|
||||
ss.state,
|
||||
ss.previous_end_time,
|
||||
ss.start_time,
|
||||
ss.end_time
|
||||
from
|
||||
session s,
|
||||
session_state ss
|
||||
where
|
||||
s.public_id = ss.session_id;
|
||||
|
||||
create domain wt_tagpair as text
|
||||
check(
|
||||
value is not null
|
||||
and
|
||||
length(trim(value)) > 0
|
||||
and
|
||||
length(trim(value)) <= 512
|
||||
and
|
||||
lower(trim(value)) = value
|
||||
);
|
||||
comment on domain wt_tagpair is
|
||||
'Text field with constraints for key/value pairs';
|
||||
|
||||
create table server_tag (
|
||||
server_id text
|
||||
references server(private_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
key wt_tagpair,
|
||||
value wt_tagpair,
|
||||
primary key(server_id, key, value)
|
||||
);
|
||||
|
||||
commit;
|
||||
@@ -4,8 +4,8 @@ package schema
|
||||
|
||||
func init() {
|
||||
migrationStates["postgres"] = migrationState{
|
||||
devMigration: false,
|
||||
binarySchemaVersion: 69,
|
||||
devMigration: true,
|
||||
binarySchemaVersion: 1001,
|
||||
upMigrations: map[int][]byte{
|
||||
1: []byte(`
|
||||
begin;
|
||||
@@ -2930,6 +2930,7 @@ before insert on target_tcp
|
||||
|
||||
|
||||
-- target_all_subtypes is a union of all target subtypes
|
||||
-- NOTE: this is replaced in 100 to add worker_filter
|
||||
create view target_all_subtypes
|
||||
as
|
||||
select
|
||||
@@ -3127,6 +3128,7 @@ begin;
|
||||
endpoint text -- not part of the warehouse, used to send info to the worker
|
||||
);
|
||||
|
||||
-- Replaced in 100 to add worker_filter
|
||||
create trigger
|
||||
immutable_columns
|
||||
before
|
||||
@@ -3422,6 +3424,7 @@ begin;
|
||||
create trigger insert_session_state before insert on session_state
|
||||
for each row execute procedure insert_session_state();
|
||||
|
||||
-- Replaced in 100 to add worker_filter
|
||||
create view session_with_state as
|
||||
select
|
||||
s.public_id,
|
||||
@@ -4861,6 +4864,131 @@ begin;
|
||||
|
||||
commit;
|
||||
|
||||
`),
|
||||
1001: []byte(`
|
||||
begin;
|
||||
|
||||
-- This series of expressions fixes the primary key on the server table
|
||||
alter table session
|
||||
drop constraint session_server_id_server_type_fkey;
|
||||
alter table server
|
||||
drop constraint server_pkey;
|
||||
alter table server
|
||||
drop column name;
|
||||
alter table server
|
||||
add primary key (private_id);
|
||||
alter table server
|
||||
add constraint server_id_must_not_be_empty
|
||||
check(length(trim(private_id)) > 0);
|
||||
alter table session
|
||||
add constraint session_server_id_fkey
|
||||
foreign key (server_id)
|
||||
references server(private_id)
|
||||
on delete set null
|
||||
on update cascade;
|
||||
|
||||
create domain wt_bexprfilter as text
|
||||
check(
|
||||
value is null
|
||||
or
|
||||
(
|
||||
length(trim(value)) > 0
|
||||
and
|
||||
length(trim(value)) <= 2048
|
||||
)
|
||||
);
|
||||
comment on domain wt_bexprfilter is
|
||||
'Text field with constraints for go-bexpr filters';
|
||||
|
||||
-- Add the worker filter to the target_tcp table and session table
|
||||
alter table target_tcp
|
||||
add column worker_filter wt_bexprfilter;
|
||||
alter table session
|
||||
add column worker_filter wt_bexprfilter;
|
||||
|
||||
-- Replace the immutable columns trigger from 50 to add worker_filter
|
||||
drop trigger immutable_columns on session;
|
||||
create trigger immutable_columns
|
||||
before update on session
|
||||
for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint', 'worker_filter');
|
||||
|
||||
-- Replaces the view created in 41 to include worker_filter
|
||||
drop view target_all_subtypes;
|
||||
create view target_all_subtypes
|
||||
as
|
||||
select
|
||||
public_id,
|
||||
scope_id,
|
||||
name,
|
||||
description,
|
||||
default_port,
|
||||
session_max_seconds,
|
||||
session_connection_limit,
|
||||
version,
|
||||
create_time,
|
||||
update_time,
|
||||
worker_filter,
|
||||
'tcp' as type
|
||||
from target_tcp;
|
||||
|
||||
-- Replaces the view created in 50 to include worker_filter
|
||||
drop view session_with_state;
|
||||
create view session_with_state as
|
||||
select
|
||||
s.public_id,
|
||||
s.user_id,
|
||||
s.host_id,
|
||||
s.server_id,
|
||||
s.server_type,
|
||||
s.target_id,
|
||||
s.host_set_id,
|
||||
s.auth_token_id,
|
||||
s.scope_id,
|
||||
s.certificate,
|
||||
s.expiration_time,
|
||||
s.connection_limit,
|
||||
s.tofu_token,
|
||||
s.key_id,
|
||||
s.termination_reason,
|
||||
s.version,
|
||||
s.create_time,
|
||||
s.update_time,
|
||||
s.endpoint,
|
||||
s.worker_filter,
|
||||
ss.state,
|
||||
ss.previous_end_time,
|
||||
ss.start_time,
|
||||
ss.end_time
|
||||
from
|
||||
session s,
|
||||
session_state ss
|
||||
where
|
||||
s.public_id = ss.session_id;
|
||||
|
||||
create domain wt_tagpair as text
|
||||
check(
|
||||
value is not null
|
||||
and
|
||||
length(trim(value)) > 0
|
||||
and
|
||||
length(trim(value)) <= 512
|
||||
and
|
||||
lower(trim(value)) = value
|
||||
);
|
||||
comment on domain wt_tagpair is
|
||||
'Text field with constraints for key/value pairs';
|
||||
|
||||
create table server_tag (
|
||||
server_id text
|
||||
references server(private_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
key wt_tagpair,
|
||||
value wt_tagpair,
|
||||
primary key(server_id, key, value)
|
||||
);
|
||||
|
||||
commit;
|
||||
`),
|
||||
},
|
||||
downMigrations: map[int][]byte{
|
||||
@@ -5216,6 +5344,16 @@ begin;
|
||||
|
||||
commit;
|
||||
|
||||
`),
|
||||
1001: []byte(`
|
||||
begin;
|
||||
|
||||
drop domain wt_bexprfilter;
|
||||
|
||||
drop table server_tag;
|
||||
drop domain wt_tagpair;
|
||||
|
||||
commit;
|
||||
`),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user