Skip to content

Commit c5b0767

Browse files
authored
Implement profile update (#1566)
This implements the profile update method in the minder server. This was done last as it's kinda complex... as you can tell from the PR. We have to verify that the new profile is valid, that certain values like the project, name and provider don't change. Then we update the rules, and clean up the unused ones. And keep the instantiations in check. This, however, will be a very nice usability improvement. This also adds a profile update command
1 parent 7392747 commit c5b0767

File tree

16 files changed

+2604
-1369
lines changed

16 files changed

+2604
-1369
lines changed

cmd/cli/app/profile/profile_update.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//
2+
// Copyright 2023 Stacklok, Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package profile
17+
18+
import (
19+
"fmt"
20+
"io"
21+
"os"
22+
"path/filepath"
23+
24+
"github.com/spf13/cobra"
25+
"github.com/spf13/viper"
26+
27+
"github.com/stacklok/minder/internal/engine"
28+
"github.com/stacklok/minder/internal/util"
29+
pb "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1"
30+
)
31+
32+
// Profile_updateCmd represents the profile update command
33+
var Profile_updateCmd = &cobra.Command{
34+
Use: "update",
35+
Short: "Update a profile within a minder control plane",
36+
Long: `The minder profile update subcommand lets you update profiles for a project
37+
within a minder control plane.`,
38+
PreRun: func(cmd *cobra.Command, args []string) {
39+
if err := viper.BindPFlags(cmd.Flags()); err != nil {
40+
fmt.Fprintf(os.Stderr, "Error binding flags: %s\n", err)
41+
}
42+
},
43+
RunE: func(cmd *cobra.Command, args []string) error {
44+
f := util.GetConfigValue(viper.GetViper(), "file", "file", cmd, "").(string)
45+
proj := viper.GetString("project")
46+
47+
var err error
48+
49+
var preader io.Reader
50+
51+
if f == "" {
52+
return fmt.Errorf("error: file must be set")
53+
}
54+
55+
if f == "-" {
56+
preader = os.Stdin
57+
} else {
58+
f = filepath.Clean(f)
59+
fopen, err := os.Open(f)
60+
if err != nil {
61+
return fmt.Errorf("error opening file: %w", err)
62+
}
63+
64+
defer fopen.Close()
65+
66+
preader = fopen
67+
}
68+
69+
conn, err := util.GrpcForCommand(cmd, viper.GetViper())
70+
util.ExitNicelyOnError(err, "Error getting grpc connection")
71+
defer conn.Close()
72+
73+
client := pb.NewProfileServiceClient(conn)
74+
ctx, cancel := util.GetAppContext()
75+
defer cancel()
76+
77+
p, err := engine.ParseYAML(preader)
78+
if err != nil {
79+
return fmt.Errorf("error reading profile from file: %w", err)
80+
}
81+
82+
if proj != "" {
83+
if p.Context == nil {
84+
p.Context = &pb.Context{}
85+
}
86+
87+
p.Context.Project = &proj
88+
}
89+
90+
// update a profile
91+
resp, err := client.UpdateProfile(ctx, &pb.UpdateProfileRequest{
92+
Profile: p,
93+
})
94+
if err != nil {
95+
return fmt.Errorf("error updating profile: %w", err)
96+
}
97+
98+
table := initializeTable(cmd)
99+
renderProfileTable(resp.GetProfile(), table)
100+
table.Render()
101+
return nil
102+
},
103+
}
104+
105+
func init() {
106+
ProfileCmd.AddCommand(Profile_updateCmd)
107+
Profile_updateCmd.Flags().StringP("file", "f", "", "Path to the YAML defining the profile (or - for stdin)")
108+
Profile_updateCmd.Flags().StringP("project", "p", "", "Project to update the profile in")
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- Copyright 2023 Stacklok, Inc
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
-- drop index
16+
DROP INDEX IF EXISTS entity_profiles_unique;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-- Copyright 2023 Stacklok, Inc
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
-- We may only have a single entity profile per profile+entity combination,
16+
-- so we can use a unique index to enforce this.
17+
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS entity_profiles_unique ON
18+
entity_profiles (entity, profile_id);

database/mock/store.go

+124-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

database/query/profile_status.sql

+9
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ SELECT p.id, p.name, ps.profile_status, ps.last_updated FROM profile_status ps
7272
INNER JOIN profiles p ON p.id = ps.profile_id
7373
WHERE p.project_id = $1;
7474

75+
-- DeleteRuleStatusesForProfileAndRuleType deletes a rule evaluation
76+
-- but locks the table before doing so.
77+
78+
-- name: DeleteRuleStatusesForProfileAndRuleType :exec
79+
DELETE FROM rule_evaluations
80+
WHERE id IN (
81+
SELECT id FROM rule_evaluations as re
82+
WHERE re.profile_id = $1 AND re.rule_type_id = $2 FOR UPDATE);
83+
7584
-- name: ListRuleEvaluationsByProfileId :many
7685
WITH
7786
eval_details AS (

0 commit comments

Comments
 (0)