diff --git a/internal/jujuapi/access_control.go b/internal/jujuapi/access_control.go index b4de5f247..8218734a6 100644 --- a/internal/jujuapi/access_control.go +++ b/internal/jujuapi/access_control.go @@ -58,6 +58,23 @@ func (r *controllerRoot) AddGroup(ctx context.Context, req apiparams.AddGroupReq return resp, nil } +// GetGroup returns group information based on a group ID. +func (r *controllerRoot) GetGroup(ctx context.Context, req apiparams.GetGroupRequest) (apiparams.Group, error) { + const op = errors.Op("jujuapi.GetGroup") + + groupEntry, err := r.jimm.GetGroupByID(ctx, r.user, req.UUID) + if err != nil { + zapctx.Error(ctx, "failed to get group", zaputil.Error(err)) + return apiparams.Group{}, errors.E(op, err) + } + return apiparams.Group{ + UUID: groupEntry.UUID, + Name: groupEntry.Name, + CreatedAt: groupEntry.CreatedAt.Format(time.RFC3339), + UpdatedAt: groupEntry.UpdatedAt.Format(time.RFC3339), + }, nil +} + // RenameGroup renames a group within JIMMs DB for reference by OpenFGA. func (r *controllerRoot) RenameGroup(ctx context.Context, req apiparams.RenameGroupRequest) error { const op = errors.Op("jujuapi.RenameGroup") diff --git a/internal/jujuapi/access_control_test.go b/internal/jujuapi/access_control_test.go index e1230590b..544a97fed 100644 --- a/internal/jujuapi/access_control_test.go +++ b/internal/jujuapi/access_control_test.go @@ -61,6 +61,23 @@ func (s *accessControlSuite) TestAddGroup(c *gc.C) { c.Assert(err, gc.ErrorMatches, ".*already exists.*") } +func (s *accessControlSuite) TestGetGroup(c *gc.C) { + conn := s.open(c, nil, "alice") + defer conn.Close() + + client := api.NewClient(conn) + + created, err := client.AddGroup(&apiparams.AddGroupRequest{Name: "test-group"}) + c.Assert(err, jc.ErrorIsNil) + + retrieved, err := client.GetGroup(&apiparams.GetGroupRequest{UUID: created.UUID}) + c.Assert(err, jc.ErrorIsNil) + c.Assert(retrieved.Group, gc.DeepEquals, created.Group) + + _, err = client.GetGroup(&apiparams.GetGroupRequest{UUID: "non-existent"}) + c.Assert(err, gc.ErrorMatches, ".*not found.*") +} + func (s *accessControlSuite) TestRemoveGroup(c *gc.C) { conn := s.open(c, nil, "alice") defer conn.Close() diff --git a/internal/jujuapi/jimm.go b/internal/jujuapi/jimm.go index f52551eea..1fad49918 100644 --- a/internal/jujuapi/jimm.go +++ b/internal/jujuapi/jimm.go @@ -41,6 +41,7 @@ func init() { addCloudToControllerMethod := rpc.Method(r.AddCloudToController) removeCloudFromControllerMethod := rpc.Method(r.RemoveCloudFromController) addGroupMethod := rpc.Method(r.AddGroup) + getGroupMethod := rpc.Method(r.GetGroup) renameGroupMethod := rpc.Method(r.RenameGroup) removeGroupMethod := rpc.Method(r.RemoveGroup) listGroupsMethod := rpc.Method(r.ListGroups) @@ -76,6 +77,7 @@ func init() { r.AddMethod("JIMM", 4, "MigrateModel", migrateModel) // JIMM ReBAC RPC r.AddMethod("JIMM", 4, "AddGroup", addGroupMethod) + r.AddMethod("JIMM", 4, "GetGroup", getGroupMethod) r.AddMethod("JIMM", 4, "RenameGroup", renameGroupMethod) r.AddMethod("JIMM", 4, "RemoveGroup", removeGroupMethod) r.AddMethod("JIMM", 4, "ListGroups", listGroupsMethod) diff --git a/pkg/api/client.go b/pkg/api/client.go index 75b002e78..79307dc9a 100644 --- a/pkg/api/client.go +++ b/pkg/api/client.go @@ -123,6 +123,13 @@ func (c *Client) AddGroup(req *params.AddGroupRequest) (params.AddGroupResponse, return resp, err } +// GetGroup returns the group with the given UUID. +func (c *Client) GetGroup(req *params.GetGroupRequest) (params.GetGroupResponse, error) { + var resp params.GetGroupResponse + err := c.caller.APICall("JIMM", 4, "", "GetGroup", req, &resp) + return resp, err +} + // RenameGroup renames a group in JIMM. func (c *Client) RenameGroup(req *params.RenameGroupRequest) error { return c.caller.APICall("JIMM", 4, "", "RenameGroup", req, nil) diff --git a/pkg/api/params/params.go b/pkg/api/params/params.go index 7098f64a4..60aa855bd 100644 --- a/pkg/api/params/params.go +++ b/pkg/api/params/params.go @@ -285,6 +285,17 @@ type AddGroupResponse struct { Group } +// GetGroupRequest holds a request to get a group. +type GetGroupRequest struct { + // UUID holds the UUID of the group to be retrieved. + UUID string `json:"uuid"` +} + +// GetGroupResponse holds the details of the group. +type GetGroupResponse struct { + Group +} + // RenameGroupRequest holds a request to rename a group. type RenameGroupRequest struct { // Name holds the name of the group.