Skip to content

Commit

Permalink
CSS-6952 add service account command (#1141)
Browse files Browse the repository at this point in the history
* Add CLI command and tests for addServiceAccount

* Hook up GoCheck to test runner

* Test for addServiceAccount CLI method

* Extend test

* PR comments

* PR comments

updated godoc
  • Loading branch information
kian99 authored Jan 30, 2024
1 parent 984fc21 commit 31e87ee
Show file tree
Hide file tree
Showing 28 changed files with 324 additions and 108 deletions.
5 changes: 5 additions & 0 deletions api/jimm.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,8 @@ func (c *Client) MigrateModel(req *params.MigrateModelRequest) (*jujuparams.Init
err := c.caller.APICall("JIMM", 4, "", "MigrateModel", req, &response)
return &response, err
}

// AddServiceAccount binds a service account to a user allowing them to manage it.
func (c *Client) AddServiceAccount(req *params.AddServiceAccountRequest) error {
return c.caller.APICall("JIMM", 4, "", "AddServiceAccount", req, nil)
}
7 changes: 4 additions & 3 deletions cmd/jimmctl/cmd/addcloudtocontroller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/dbmodel"
"github.com/canonical/jimm/internal/errors"
"github.com/canonical/jimm/internal/openfga"
ofganames "github.com/canonical/jimm/internal/openfga/names"
)

type addCloudToControllerSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&addCloudToControllerSuite{})

func (s *addCloudToControllerSuite) SetUpTest(c *gc.C) {
s.jimmSuite.SetUpTest(c)
s.JimmCmdSuite.SetUpTest(c)

// We add user bob, who is a JIMM administrator.
err := s.JIMM.Database.UpdateIdentity(context.Background(), &dbmodel.Identity{
Expand Down Expand Up @@ -166,7 +167,7 @@ clouds:
c.Log(test.about)
tmpfile, cleanupFunc := writeTempFile(c, test.cloudInfo)

bClient := s.userBakeryClient("bob@external")
bClient := s.UserBakeryClient("bob@external")
// Running the command succeeds
newCmd := cmd.NewAddCloudToControllerCommandForTesting(s.ClientStore(), bClient, test.cloudByNameFunc)
var err error
Expand Down
7 changes: 4 additions & 3 deletions cmd/jimmctl/cmd/addcontroller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import (

apiparams "github.com/canonical/jimm/api/params"
"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/jimmtest"
)

type addControllerSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&addControllerSuite{})
Expand All @@ -37,7 +38,7 @@ func (s *addControllerSuite) TestAddControllerSuperuser(c *gc.C) {
defer os.RemoveAll(tmpdir)

// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
ctx, err := cmdtesting.RunCommand(c, cmd.NewAddControllerCommandForTesting(s.ClientStore(), bClient), tmpfile)
c.Assert(err, gc.IsNil)
c.Assert(cmdtesting.Stdout(ctx), gc.Matches, `name: controller-1
Expand Down Expand Up @@ -100,7 +101,7 @@ func (s *addControllerSuite) TestAddController(c *gc.C) {
defer os.RemoveAll(tmpdir)

// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewAddControllerCommandForTesting(s.ClientStore(), bClient), tmpfile)
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/jimmctl/cmd/controllerinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
)

type controllerInfoSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&controllerInfoSuite{})
Expand Down
5 changes: 3 additions & 2 deletions cmd/jimmctl/cmd/crossmodelquery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/jimmtest"
"github.com/juju/cmd/v3/cmdtesting"
jujuparams "github.com/juju/juju/rpc/params"
Expand All @@ -15,15 +16,15 @@ import (
)

type crossModelQuerySuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&crossModelQuerySuite{})

func (s *crossModelQuerySuite) TestCrossModelQueryCommand(c *gc.C) {
// Test setup.
store := s.ClientStore()
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")

s.AddController(c, "controller-2", s.APIInfo(c))
cct := names.NewCloudCredentialTag(jimmtest.TestCloudName + "/alice@external/cred")
Expand Down
7 changes: 4 additions & 3 deletions cmd/jimmctl/cmd/grantauditlogaccess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,26 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
)

type grantAuditLogAccessSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

// TODO (alesstimec) uncomment once granting/revoking is reimplemented
//var _ = gc.Suite(&grantAuditLogAccessSuite{})

func (s *grantAuditLogAccessSuite) TestGrantAuditLogAccessSuperuser(c *gc.C) {
// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
_, err := cmdtesting.RunCommand(c, cmd.NewGrantAuditLogAccessCommandForTesting(s.ClientStore(), bClient), "bob@external")
c.Assert(err, gc.IsNil)
}

func (s *grantAuditLogAccessSuite) TestGrantAuditLogAccess(c *gc.C) {
// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewGrantAuditLogAccessCommandForTesting(s.ClientStore(), bClient), "bob@external")
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}
33 changes: 17 additions & 16 deletions cmd/jimmctl/cmd/group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,95 +11,96 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/dbmodel"
)

type groupSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&groupSuite{})

func (s *groupSuite) TestAddGroupSuperuser(c *gc.C) {
// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
_, err := cmdtesting.RunCommand(c, cmd.NewAddGroupCommandForTesting(s.ClientStore(), bClient), "test-group")
c.Assert(err, gc.IsNil)

group := &dbmodel.GroupEntry{Name: "test-group"}
err = s.jimmSuite.JIMM.Database.GetGroup(context.TODO(), group)
err = s.JimmCmdSuite.JIMM.Database.GetGroup(context.TODO(), group)
c.Assert(err, gc.IsNil)
c.Assert(group.ID, gc.Equals, uint(1))
c.Assert(group.Name, gc.Equals, "test-group")
}

func (s *groupSuite) TestAddGroup(c *gc.C) {
// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewAddGroupCommandForTesting(s.ClientStore(), bClient), "test-group")
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}

func (s *groupSuite) TestRenameGroupSuperuser(c *gc.C) {
// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")

err := s.jimmSuite.JIMM.Database.AddGroup(context.TODO(), "test-group")
err := s.JimmCmdSuite.JIMM.Database.AddGroup(context.TODO(), "test-group")
c.Assert(err, gc.IsNil)

_, err = cmdtesting.RunCommand(c, cmd.NewRenameGroupCommandForTesting(s.ClientStore(), bClient), "test-group", "renamed-group")
c.Assert(err, gc.IsNil)

group := &dbmodel.GroupEntry{Name: "renamed-group"}
err = s.jimmSuite.JIMM.Database.GetGroup(context.TODO(), group)
err = s.JimmCmdSuite.JIMM.Database.GetGroup(context.TODO(), group)
c.Assert(err, gc.IsNil)
c.Assert(group.ID, gc.Equals, uint(1))
c.Assert(group.Name, gc.Equals, "renamed-group")
}

func (s *groupSuite) TestRenameGroup(c *gc.C) {
// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewRenameGroupCommandForTesting(s.ClientStore(), bClient), "test-group", "renamed-group")
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}

func (s *groupSuite) TestRemoveGroupSuperuser(c *gc.C) {
// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")

err := s.jimmSuite.JIMM.Database.AddGroup(context.TODO(), "test-group")
err := s.JimmCmdSuite.JIMM.Database.AddGroup(context.TODO(), "test-group")
c.Assert(err, gc.IsNil)

_, err = cmdtesting.RunCommand(c, cmd.NewRemoveGroupCommandForTesting(s.ClientStore(), bClient), "test-group", "-y")
c.Assert(err, gc.IsNil)

group := &dbmodel.GroupEntry{Name: "test-group"}
err = s.jimmSuite.JIMM.Database.GetGroup(context.TODO(), group)
err = s.JimmCmdSuite.JIMM.Database.GetGroup(context.TODO(), group)
c.Assert(err, gc.ErrorMatches, "record not found")
}

func (s *groupSuite) TestRemoveGroupWithoutFlag(c *gc.C) {
// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")

_, err := cmdtesting.RunCommand(c, cmd.NewRemoveGroupCommandForTesting(s.ClientStore(), bClient), "test-group")
c.Assert(err.Error(), gc.Matches, "Failed to read from input.")
}

func (s *groupSuite) TestRemoveGroup(c *gc.C) {
// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewRemoveGroupCommandForTesting(s.ClientStore(), bClient), "test-group", "-y")
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}

func (s *groupSuite) TestListGroupsSuperuser(c *gc.C) {
// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")

for i := 0; i < 3; i++ {
err := s.jimmSuite.JIMM.Database.AddGroup(context.TODO(), fmt.Sprint("test-group", i))
err := s.JimmCmdSuite.JIMM.Database.AddGroup(context.TODO(), fmt.Sprint("test-group", i))
c.Assert(err, gc.IsNil)
}

Expand All @@ -113,7 +114,7 @@ func (s *groupSuite) TestListGroupsSuperuser(c *gc.C) {

func (s *groupSuite) TestListGroups(c *gc.C) {
// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewListGroupsCommandForTesting(s.ClientStore(), bClient), "test-group")
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}
5 changes: 3 additions & 2 deletions cmd/jimmctl/cmd/importcloudcredentials_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/dbmodel"
)

type importCloudCredentialsSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&importCloudCredentialsSuite{})
Expand Down Expand Up @@ -62,7 +63,7 @@ func (s *importCloudCredentialsSuite) TestImportCloudCredentials(c *gc.C) {
c.Assert(err, gc.IsNil)

// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
_, err = cmdtesting.RunCommand(c, cmd.NewImportCloudCredentialsCommandForTesting(s.ClientStore(), bClient), tmpfile)
c.Assert(err, gc.IsNil)

Expand Down
17 changes: 9 additions & 8 deletions cmd/jimmctl/cmd/importmodel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/dbmodel"
"github.com/canonical/jimm/internal/jimmtest"
)

type importModelSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&importModelSuite{})
Expand All @@ -42,7 +43,7 @@ func (s *importModelSuite) TestImportModelSuperuser(c *gc.C) {
defer m.Close()

// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
_, err = cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient), "controller-1", m.ModelUUID())
c.Assert(err, gc.IsNil)

Expand All @@ -69,7 +70,7 @@ func (s *importModelSuite) TestImportModelFromLocalUser(c *gc.C) {
c.Assert(err, gc.Equals, nil)

// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
_, err = cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient), "controller-1", mt.Id(), "--owner", "alice@external")
c.Assert(err, gc.IsNil)

Expand Down Expand Up @@ -100,31 +101,31 @@ func (s *importModelSuite) TestImportModelUnauthorized(c *gc.C) {
defer m.Close()

// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err = cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient), "controller-1", m.ModelUUID())
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}

func (s *importModelSuite) TestImportModelNoController(c *gc.C) {
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient))
c.Assert(err, gc.ErrorMatches, `controller not specified`)
}

func (s *importModelSuite) TestImportModelNoModelUUID(c *gc.C) {
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient), "controller-id")
c.Assert(err, gc.ErrorMatches, `model uuid not specified`)
}

func (s *importModelSuite) TestImportModelInvalidModelUUID(c *gc.C) {
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient), "controller-id", "not-a-uuid")
c.Assert(err, gc.ErrorMatches, `invalid model uuid`)
}

func (s *importModelSuite) TestImportModelTooManyArgs(c *gc.C) {
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewImportModelCommandForTesting(s.ClientStore(), bClient), "controller-id", "not-a-uuid", "spare-argument")
c.Assert(err, gc.ErrorMatches, `too many args`)
}
7 changes: 4 additions & 3 deletions cmd/jimmctl/cmd/listauditevents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (
gc "gopkg.in/check.v1"

"github.com/canonical/jimm/cmd/jimmctl/cmd"
"github.com/canonical/jimm/internal/cmdtest"
"github.com/canonical/jimm/internal/jimmtest"
)

type listAuditEventsSuite struct {
jimmSuite
cmdtest.JimmCmdSuite
}

var _ = gc.Suite(&listAuditEventsSuite{})
Expand All @@ -26,7 +27,7 @@ func (s *listAuditEventsSuite) TestListAuditEventsSuperuser(c *gc.C) {
s.AddModel(c, names.NewUserTag("charlie@external"), "model-2", names.NewCloudTag(jimmtest.TestCloudName), jimmtest.TestCloudRegionName, cct)

// alice is superuser
bClient := s.userBakeryClient("alice")
bClient := s.UserBakeryClient("alice")
context, err := cmdtesting.RunCommand(c, cmd.NewListAuditEventsCommandForTesting(s.ClientStore(), bClient))
c.Assert(err, gc.IsNil)
c.Assert(cmdtesting.Stdout(context), gc.Matches,
Expand Down Expand Up @@ -65,7 +66,7 @@ func (s *listAuditEventsSuite) TestListAuditEventsStatus(c *gc.C) {
s.AddModel(c, names.NewUserTag("charlie@external"), "model-2", names.NewCloudTag(jimmtest.TestCloudName), jimmtest.TestCloudRegionName, cct)

// bob is not superuser
bClient := s.userBakeryClient("bob")
bClient := s.UserBakeryClient("bob")
_, err := cmdtesting.RunCommand(c, cmd.NewListAuditEventsCommandForTesting(s.ClientStore(), bClient))
c.Assert(err, gc.ErrorMatches, `unauthorized \(unauthorized access\)`)
}
Loading

0 comments on commit 31e87ee

Please sign in to comment.