-
Notifications
You must be signed in to change notification settings - Fork 114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[A2-815] list rules with staged and current rules #646
Changes from all commits
5b2a918
89e1949
fc73212
a7f5cfa
c36e11d
20977cf
888f100
56ea291
b97fd6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,6 +111,8 @@ message ProjectRule { | |
string name = 3; | ||
ProjectRuleTypes type = 4; | ||
repeated Condition conditions = 5; | ||
bool deleted = 6; | ||
string status = 7; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OMG why no enum?!!! I hear you -- but it's just so annoying to convert three different kinds of enums (storage layer, authz-service GRPC, automate-gateway GRPC), and I'm not convinced it's worth it. Happy to listen to arguments, but maybe we can just make our lives a little brighter and our PRs a little smaller. π Also, in the external API (automate-gateway), we can (and should) still use an enum. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really like the compromise of having an enum at the gateway and not in the domain layer. The enum unwrapping code is super super annoying. |
||
} | ||
|
||
enum ProjectRuleTypes { | ||
|
@@ -173,7 +175,9 @@ message GetRuleResp { | |
ProjectRule rule = 1; | ||
} | ||
|
||
message ListRulesReq {} | ||
message ListRulesReq { | ||
bool include_staged = 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. βΉοΈ Pass |
||
} | ||
|
||
message ListRulesResp { | ||
repeated ProjectRule rules = 1; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ import ( | |
"github.com/chef/automate/lib/grpc/grpctest" | ||
) | ||
|
||
const applied = "applied" | ||
|
||
func TestCreateRule(t *testing.T) { | ||
ctx := context.Background() | ||
cl, store, _, _ := setupRules(t) | ||
|
@@ -143,6 +145,7 @@ func TestCreateRule(t *testing.T) { | |
Operator: api.ProjectRuleConditionOperators_MEMBER_OF, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. βΉοΈI haven't added any tests on that layer yet. |
||
}, | ||
}, | ||
Status: applied, | ||
}, | ||
}, resp) | ||
}}, | ||
|
@@ -470,6 +473,7 @@ func TestGetRule(t *testing.T) { | |
Type: api.ProjectRuleTypes_NODE, | ||
ProjectId: projectID, | ||
Conditions: apiConditions, | ||
Status: applied, | ||
} | ||
|
||
resp, err := cl.GetRule(ctx, &api.GetRuleReq{Id: id}) | ||
|
@@ -544,13 +548,15 @@ func TestListRules(t *testing.T) { | |
Type: api.ProjectRuleTypes_NODE, | ||
ProjectId: projectID, | ||
Conditions: apiConditions1, | ||
Status: applied, | ||
} | ||
expected2 := api.ProjectRule{ | ||
Id: id2, | ||
Name: name, | ||
Type: api.ProjectRuleTypes_EVENT, | ||
ProjectId: projectID, | ||
Conditions: apiConditions2, | ||
Status: applied, | ||
} | ||
expected := []*api.ProjectRule{&expected1, &expected2} | ||
|
||
|
@@ -584,9 +590,9 @@ func TestListRulesForProject(t *testing.T) { | |
} | ||
apiConditions2 := []*api.Condition{ | ||
{ | ||
Attribute: api.ProjectRuleConditionAttributes_CHEF_ORGS, | ||
Values: []string{"chef"}, | ||
Operator: api.ProjectRuleConditionOperators_EQUALS, | ||
Attribute: api.ProjectRuleConditionAttributes_CHEF_ORGS, | ||
Values: []string{"chef"}, | ||
Operator: api.ProjectRuleConditionOperators_EQUALS, | ||
}, | ||
} | ||
storageConditions2 := []storage.Condition{ | ||
|
@@ -599,9 +605,9 @@ func TestListRulesForProject(t *testing.T) { | |
} | ||
apiConditions3 := []*api.Condition{ | ||
{ | ||
Attribute: api.ProjectRuleConditionAttributes_CHEF_ORGS, | ||
Values: []string{"other", "org"}, | ||
Operator: api.ProjectRuleConditionOperators_MEMBER_OF, | ||
Attribute: api.ProjectRuleConditionAttributes_CHEF_ORGS, | ||
Values: []string{"other", "org"}, | ||
Operator: api.ProjectRuleConditionOperators_MEMBER_OF, | ||
}, | ||
} | ||
storageConditions3 := []storage.Condition{ | ||
|
@@ -643,13 +649,15 @@ func TestListRulesForProject(t *testing.T) { | |
Type: api.ProjectRuleTypes_EVENT, | ||
ProjectId: projectID2, | ||
Conditions: apiConditions2, | ||
Status: applied, | ||
} | ||
expected3 := api.ProjectRule{ | ||
Id: id3, | ||
Name: name, | ||
Type: api.ProjectRuleTypes_EVENT, | ||
ProjectId: projectID2, | ||
Conditions: apiConditions3, | ||
Status: applied, | ||
} | ||
expected := []*api.ProjectRule{&expected2, &expected3} | ||
|
||
|
@@ -746,6 +754,7 @@ func addRuleToStore(t *testing.T, store *cache.Cache, id, name string, ruleType | |
Type: ruleType, | ||
ProjectID: projectID, | ||
Conditions: conditions, | ||
Status: applied, | ||
} | ||
store.Add(id, rule, 0) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
BEGIN; | ||
|
||
CREATE OR REPLACE FUNCTION | ||
query_staged_and_applied_rules(_project_filter TEXT[]) | ||
RETURNS setof json AS $$ | ||
|
||
-- fetch staged rules | ||
SELECT json_build_object( | ||
'id', r.id, | ||
'project_id', r.project_id, | ||
'name', r.name, | ||
'type', r.type, | ||
'deleted', r.deleted, | ||
'status', 'staged', | ||
'conditions', json_agg( | ||
json_build_object( | ||
'value', rc.value, | ||
'operator', rc.operator, | ||
'attribute', rc.attribute | ||
) | ||
) | ||
) AS rules | ||
FROM iam_staged_project_rules AS r | ||
INNER JOIN iam_staged_rule_conditions AS rc ON rc.rule_db_id=r.db_id | ||
WHERE projects_match_for_rule(project_id, _project_filter) | ||
GROUP BY r.id, r.project_id, r.name, r.type, r.deleted | ||
|
||
UNION ALL | ||
|
||
-- fetch applied rules | ||
SELECT json_build_object( | ||
'id', r.id, | ||
'project_id', r.project_id, | ||
'name', r.name, | ||
'type', r.type, | ||
'deleted', false, | ||
'status', 'applied', | ||
'conditions', json_agg( | ||
json_build_object( | ||
'value', rc.value, | ||
'operator', rc.operator, | ||
'attribute', rc.attribute | ||
) | ||
) | ||
) AS rules | ||
FROM iam_project_rules AS r | ||
INNER JOIN iam_rule_conditions AS rc ON rc.rule_db_id=r.db_id | ||
WHERE projects_match_for_rule(project_id, _project_filter) | ||
GROUP BY r.id, r.project_id, r.name, r.type; | ||
|
||
$$ LANGUAGE sql; | ||
|
||
DROP FUNCTION IF EXISTS query_staged_rule(_rule_id TEXT, _project_filter TEXT[]); | ||
|
||
CREATE OR REPLACE FUNCTION | ||
query_staged_or_applied_rule(_rule_id TEXT, _project_filter TEXT[]) | ||
RETURNS json AS $$ | ||
|
||
-- check for applied rule | ||
SELECT json_build_object( | ||
'id', r.id, | ||
'project_id', r.project_id, | ||
'name', r.name, | ||
'type', r.type, | ||
'deleted', r.deleted, | ||
'status', 'staged', | ||
'conditions', json_agg( | ||
json_build_object( | ||
'value', rc.value, | ||
'operator', rc.operator, | ||
'attribute', rc.attribute | ||
) | ||
) | ||
) AS rule | ||
FROM iam_staged_project_rules AS r | ||
INNER JOIN iam_staged_rule_conditions AS rc ON rc.rule_db_id=r.db_id | ||
WHERE id=_rule_id AND projects_match_for_rule(project_id, _project_filter) | ||
GROUP BY r.id, r.project_id, r.name, r.type, r.deleted | ||
|
||
UNION ALL | ||
|
||
-- check for applied rule | ||
SELECT json_build_object( | ||
'id', r.id, | ||
'project_id', r.project_id, | ||
'name', r.name, | ||
'type', r.type, | ||
'deleted', false, | ||
'status', 'applied', | ||
'conditions', json_agg( | ||
json_build_object( | ||
'value', rc.value, | ||
'operator', rc.operator, | ||
'attribute', rc.attribute | ||
) | ||
) | ||
) AS rule | ||
FROM iam_project_rules AS r | ||
INNER JOIN iam_rule_conditions AS rc ON rc.rule_db_id=r.db_id | ||
WHERE id=_rule_id AND projects_match_for_rule(project_id, _project_filter) | ||
GROUP BY r.id, r.project_id, r.name, r.type; | ||
|
||
$$ LANGUAGE sql; | ||
|
||
CREATE OR REPLACE FUNCTION | ||
query_rules(_project_filter TEXT[]) | ||
RETURNS setof json AS $$ | ||
|
||
SELECT json_build_object( | ||
'id', r.id, | ||
'project_id', r.project_id, | ||
'name', r.name, | ||
'type', r.type, | ||
'status', 'applied', | ||
'conditions', json_agg( | ||
json_build_object( | ||
'value', rc.value, | ||
'operator', rc.operator, | ||
'attribute', rc.attribute | ||
) | ||
) | ||
) AS rule | ||
FROM iam_project_rules AS r | ||
INNER JOIN iam_rule_conditions AS rc ON rc.rule_db_id=r.db_id | ||
WHERE projects_match_for_rule(project_id, _project_filter) | ||
GROUP BY r.id, r.project_id, r.name, r.type; | ||
|
||
$$ LANGUAGE sql; | ||
|
||
CREATE OR REPLACE FUNCTION | ||
query_rules_for_project(_project_id TEXT, _project_filter TEXT[]) | ||
RETURNS setof json AS $$ | ||
|
||
SELECT json_build_object( | ||
'id', r.id, | ||
'project_id', r.project_id, | ||
'name', r.name, | ||
'type', r.type, | ||
'status', 'applied', | ||
'conditions', json_agg( | ||
json_build_object( | ||
'value', rc.value, | ||
'operator', rc.operator, | ||
'attribute', rc.attribute | ||
) | ||
) | ||
) AS rule | ||
FROM iam_project_rules AS r | ||
INNER JOIN iam_rule_conditions AS rc | ||
ON rc.rule_db_id=r.db_id | ||
WHERE _project_id=project_id AND projects_match_for_rule(project_id, _project_filter) | ||
GROUP BY r.id, r.project_id, r.name, r.type; | ||
|
||
$$ LANGUAGE sql; | ||
|
||
COMMIT; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -243,6 +243,7 @@ func (s *State) GetPolicyChangeNotifier(ctx context.Context) (v2.PolicyChangeNot | |
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. βΉοΈ Memstore adaptations. I anticipate that we all kind of have some of these in our current WIP PRs... :/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we wanna match it as close to postgres as possible, I think we'd want a staged cache and an applied cache. Is that worthwhile? Probably not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heh probably not as much WIP as we should. Left a comment in Slack. |
||
|
||
func (s *State) CreateRule(_ context.Context, rule *storage.Rule) (*storage.Rule, error) { | ||
rule.Status = "applied" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we want to match postgres behavior, the status here would be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leaving this as-is to not break all the memstore-based tests. Let's nuke them. π |
||
if err := s.rules.Add(rule.ID, rule, cache.NoExpiration); err != nil { | ||
return nil, storage_errors.ErrConflict | ||
} | ||
|
@@ -285,7 +286,7 @@ func (s *State) GetStagedOrAppliedRule(_ context.Context, id string) (*storage.R | |
return rule, nil | ||
} | ||
|
||
func (s *State) ListRules(_ context.Context) ([]*storage.Rule, error) { | ||
func (s *State) ListStagedAndAppliedRules(_ context.Context) ([]*storage.Rule, error) { | ||
items := s.rules.Items() | ||
rules := []*storage.Rule{} | ||
|
||
|
@@ -298,6 +299,19 @@ func (s *State) ListRules(_ context.Context) ([]*storage.Rule, error) { | |
return rules, nil | ||
} | ||
|
||
func (s *State) ListRules(_ context.Context) ([]*storage.Rule, error) { | ||
items := s.rules.Items() | ||
rules := []*storage.Rule{} | ||
|
||
for _, item := range items { | ||
if rule, ok := item.Object.(*storage.Rule); ok && rule.Status == "applied" { | ||
rules = append(rules, rule) | ||
} | ||
} | ||
|
||
return rules, nil | ||
} | ||
|
||
func (s *State) ListRulesForProject(_ context.Context, projectID string) ([]*storage.Rule, error) { | ||
items := s.rules.Items() | ||
rules := []*storage.Rule{} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
βΉοΈSurfacing the deleted and staged/applied status of a rule in the interservice API. Nothing done for
automate-gateway
yet.