Skip to content

Commit

Permalink
added all flag, stop leaking params and some tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
anastasiamac committed Nov 24, 2017
1 parent 8bf0512 commit 1260956
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 102 deletions.
42 changes: 42 additions & 0 deletions api/base/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,45 @@ type Filesystem struct {
Status string
Detachable bool
}

// UserModelSummary holds summary about a model for a user.
type UserModelSummary struct {
Name string
UUID string
ControllerUUID string
ProviderType string
DefaultSeries string
Cloud string
CloudRegion string
CloudCredential string
Owner string
Life string
Status Status
ModelUserAccess string
UserLastConnection *time.Time
Counts []EntityCount
AgentVersion *version.Number
Error error
Migration *MigrationSummary
SLA *SLASummary
}

// EntityCount holds a count for a particular entity, for example machines or core count.
type EntityCount struct {
Entity string
Count int64
}

// MigrationSummary holds information about a current migration attempt
// if there is one on progress.
type MigrationSummary struct {
Status string
StartTime *time.Time
EndTime *time.Time
}

// SLASummary holds information about SLA.
type SLASummary struct {
Level string
Owner string
}
81 changes: 77 additions & 4 deletions api/modelmanager/modelmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,86 @@ func (c *Client) ListModels(user string) ([]base.UserModel, error) {
return result, nil
}

func (c *Client) ListModelSummaries(user names.UserTag) ([]params.ModelSummaryResult, error) {
var results params.ModelSummaryResults
err := c.facade.FacadeCall("ListModelSummaries", params.Entity{user.String()}, &results)
func (c *Client) ListModelSummaries(user string, all bool) ([]base.UserModelSummary, error) {
var out params.ModelSummaryResults
if !names.IsValidUser(user) {
return nil, errors.Errorf("invalid user name %q", user)
}
in := params.ModelSummariesRequest{UserTag: names.NewUserTag(user).String(), All: all}
err := c.facade.FacadeCall("ListModelSummaries", in, &out)
if err != nil {
return nil, errors.Trace(err)
}
return results.Results, nil
summaries := make([]base.UserModelSummary, len(out.Results))
for i, r := range out.Results {
if r.Error != nil {
// cope with typed error
summaries[i] = base.UserModelSummary{Error: errors.Trace(r.Error)}
continue
}
summary := r.Result
summaries[i] = base.UserModelSummary{
Name: summary.Name,
UUID: summary.UUID,
ControllerUUID: summary.ControllerUUID,
ProviderType: summary.ProviderType,
DefaultSeries: summary.DefaultSeries,
CloudRegion: summary.CloudRegion,
Life: string(summary.Life),
ModelUserAccess: string(summary.UserAccess),
UserLastConnection: summary.UserLastConnection,
Counts: make([]base.EntityCount, len(summary.Counts)),
AgentVersion: summary.AgentVersion,
}
for pos, count := range summary.Counts {
summaries[i].Counts[pos] = base.EntityCount{string(count.Entity), count.Count}
}
summaries[i].Status = base.Status{
Status: summary.Status.Status,
Info: summary.Status.Info,
Data: make(map[string]interface{}),
Since: summary.Status.Since,
}
//TODO (anastasiamac 2017-11-24) do we need status data for summaries?
// we do not translate it at cmd/presentation layer and is it really a summary?...
for k, v := range summary.Status.Data {
summaries[i].Status.Data[k] = v
}
if owner, err := names.ParseUserTag(summary.OwnerTag); err != nil {
summaries[i].Error = errors.Annotatef(err, "while parsing model owner tag")
continue
} else {
summaries[i].Owner = owner.Id()
}
if cloud, err := names.ParseCloudTag(summary.CloudTag); err != nil {
summaries[i].Error = errors.Annotatef(err, "while parsing model cloud tag")
continue
} else {
summaries[i].Cloud = cloud.Id()
}
if summary.CloudCredentialTag != "" {
if credTag, err := names.ParseCloudCredentialTag(summary.CloudCredentialTag); err != nil {
summaries[i].Error = errors.Annotatef(err, "while parsing model cloud credential tag")
continue
} else {
summaries[i].CloudCredential = credTag.Id()
}
}
if summary.Migration != nil {
summaries[i].Migration = &base.MigrationSummary{
Status: summary.Migration.Status,
StartTime: summary.Migration.Start,
EndTime: summary.Migration.End,
}
}
if summary.SLA != nil {
summaries[i].SLA = &base.SLASummary{
Level: summary.SLA.Level,
Owner: summary.SLA.Owner,
}
}
}
return summaries, nil
}

func (c *Client) ModelInfo(tags []names.ModelTag) ([]params.ModelInfoResult, error) {
Expand Down
92 changes: 79 additions & 13 deletions api/modelmanager/modelmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package modelmanager_test

import (
"regexp"
"time"

"github.com/juju/errors"
Expand Down Expand Up @@ -404,59 +405,124 @@ func (s *modelmanagerSuite) TestModelStatusError(c *gc.C) {
c.Assert(out, gc.IsNil)
}

func (s *modelmanagerSuite) TesListModelSummaries(c *gc.C) {
userTag := names.NewUserTag("commander")
modelInfo := params.ModelSummary{
func createModelSummary() *params.ModelSummary {
return &params.ModelSummary{
Name: "name",
UUID: "uuid",
ControllerUUID: "controllerUUID",
ProviderType: "aws",
DefaultSeries: "xenial",
CloudTag: "cloud-aws",
CloudRegion: "us-east-1",
CloudCredentialTag: "credential-cred",
CloudCredentialTag: "cloudcred-foo_bob_one",
OwnerTag: "user-admin",
Life: params.Alive,
Status: params.EntityStatus{Status: status.Status("active")},
UserAccess: params.ModelAdminAccess,
Counts: []params.ModelEntityCount{},
}
}

func (s *modelmanagerSuite) TestListModelSummaries(c *gc.C) {
userTag := names.NewUserTag("commander")
testModelInfo := createModelSummary()

apiCaller := basetesting.BestVersionCaller{
BestVersion: 4,
APICallerFunc: func(objType string, version int, id, request string, arg, result interface{}) error {
c.Check(objType, gc.Equals, "ModelManager")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "ListModelSummaries")
c.Check(arg, gc.Equals, params.Entity{Tag: userTag.String()})
c.Check(arg, gc.Equals, params.ModelSummariesRequest{
UserTag: userTag.String(),
All: true,
})
c.Check(result, gc.FitsTypeOf, &params.ModelSummaryResults{})

out := result.(*params.ModelSummaryResults)
out.Results = []params.ModelSummaryResult{
params.ModelSummaryResult{Result: &modelInfo},
params.ModelSummaryResult{Result: testModelInfo},
params.ModelSummaryResult{Error: common.ServerError(errors.New("model error"))},
}
return nil
},
}

client := modelmanager.NewClient(apiCaller)
results, err := client.ListModelSummaries(userTag)
results, err := client.ListModelSummaries(userTag.Id(), true)
c.Assert(err, jc.ErrorIsNil)
c.Assert(results, jc.DeepEquals, []params.ModelSummaryResult{
{Result: &modelInfo},
{Error: &params.Error{Message: "model error"}},

c.Assert(results, gc.HasLen, 2)
c.Assert(results[0], jc.DeepEquals, base.UserModelSummary{Name: testModelInfo.Name,
UUID: testModelInfo.UUID,
ControllerUUID: testModelInfo.ControllerUUID,
ProviderType: testModelInfo.ProviderType,
DefaultSeries: testModelInfo.DefaultSeries,
Cloud: "aws",
CloudRegion: "us-east-1",
CloudCredential: "foo/bob/one",
Owner: "admin",
Life: "alive",
Status: base.Status{
Status: status.Active,
Data: map[string]interface{}{},
},
ModelUserAccess: "admin",
Counts: []base.EntityCount{},
})
c.Assert(errors.Cause(results[1].Error), gc.ErrorMatches, "model error")
}

func (s *modelmanagerSuite) TestListModelSummariesParsingErrors(c *gc.C) {
badOwnerInfo := createModelSummary()
badOwnerInfo.OwnerTag = "owner-user"

badCloudInfo := createModelSummary()
badCloudInfo.CloudTag = "not-cloud"

badCredentialsInfo := createModelSummary()
badCredentialsInfo.CloudCredentialTag = "not-credential"

apiCaller := basetesting.BestVersionCaller{
BestVersion: 4,
APICallerFunc: func(objType string, version int, id, request string, arg, result interface{}) error {
out := result.(*params.ModelSummaryResults)
out.Results = []params.ModelSummaryResult{
params.ModelSummaryResult{Result: badOwnerInfo},
params.ModelSummaryResult{Result: badCloudInfo},
params.ModelSummaryResult{Result: badCredentialsInfo},
}
return nil
},
}

client := modelmanager.NewClient(apiCaller)
results, err := client.ListModelSummaries("commander", true)
c.Assert(err, jc.ErrorIsNil)
c.Assert(results, gc.HasLen, 3)
c.Assert(results[0].Error, gc.ErrorMatches, `while parsing model owner tag: "owner-user" is not a valid tag`)
c.Assert(results[1].Error, gc.ErrorMatches, `while parsing model cloud tag: "not-cloud" is not a valid tag`)
c.Assert(results[2].Error, gc.ErrorMatches, `while parsing model cloud credential tag: "not-credential" is not a valid tag`)
}

func (s *modelmanagerSuite) TestListModelSummariesInvalidUserIn(c *gc.C) {
apiCaller := basetesting.APICallerFunc(
func(objType string, version int, id, request string, args, result interface{}) error {
return nil
})
client := modelmanager.NewClient(apiCaller)
out, err := client.ListModelSummaries("++)captain", false)
c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`invalid user name "++)captain"`))
c.Assert(out, gc.IsNil)
}

func (s *modelmanagerSuite) TestListModelSummariesError(c *gc.C) {
userTag := names.NewUserTag("captain")
func (s *modelmanagerSuite) TestListModelSummariesServerError(c *gc.C) {
apiCaller := basetesting.APICallerFunc(
func(objType string, version int, id, request string, args, result interface{}) error {
return errors.New("captain, error")
})
client := modelmanager.NewClient(apiCaller)
out, err := client.ListModelSummaries(userTag)
out, err := client.ListModelSummaries("captain", false)
c.Assert(err, gc.ErrorMatches, "captain, error")
c.Assert(out, gc.IsNil)
}
Expand Down
13 changes: 3 additions & 10 deletions apiserver/facades/client/modelmanager/listmodelsummaries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ func (s *ListModelsWithInfoSuite) setAPIUser(c *gc.C, user names.UserTag) {
s.api = modelmanager
}

// TODO (anastasiamac 2017-11-24) add test with migration and SLA

func (s *ListModelsWithInfoSuite) TestListModelSummaries(c *gc.C) {
result, err := s.api.ListModelSummaries(params.ModelSummariesRequest{UserTag: s.adminUser.String()})
c.Assert(err, jc.ErrorIsNil)
Expand Down Expand Up @@ -148,7 +150,7 @@ func (s *ListModelsWithInfoSuite) TestListModelSummariesWithCoreCount(c *gc.C) {
c.Assert(result.Results[0].Result.Counts[0], jc.DeepEquals, params.ModelEntityCount{params.Cores, 43})
}

func (s *ListModelsWithInfoSuite) TestListModelSummariesWithAll(c *gc.C) {
func (s *ListModelsWithInfoSuite) TestListModelSummariesWithMachineAndUserDetails(c *gc.C) {
now := time.Now()
s.st.modelDetailsForUser = func() ([]state.ModelSummary, error) {
summary := s.st.model.getModelDetails()
Expand Down Expand Up @@ -185,15 +187,6 @@ func (s *ListModelsWithInfoSuite) TestListModelSummariesWithAll(c *gc.C) {
})
}

func (s *ListModelsWithInfoSuite) TestListModelSummariesAdminListsOther(c *gc.C) {
otherTag := names.NewUserTag("someotheruser")
s.st.model = s.createModel(c, otherTag)
result, err := s.api.ListModelSummaries(params.ModelSummariesRequest{UserTag: s.adminUser.String()})
c.Assert(err, jc.ErrorIsNil)
c.Assert(result.Results, gc.HasLen, 1)
c.Assert(result.Results[0].Result.OwnerTag, gc.DeepEquals, otherTag.String())
}

func (s *ListModelsWithInfoSuite) TestListModelSummariesDenied(c *gc.C) {
user := names.NewUserTag("external@remote")
s.setAPIUser(c, user)
Expand Down
18 changes: 18 additions & 0 deletions apiserver/facades/client/modelmanager/modelmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,24 @@ func (m *ModelManagerAPI) ListModelSummaries(req params.ModelSummariesRequest) (
if err == nil {
summary.UserAccess = access
}
// TODO (anastasiamac 2017-11-24) what happens here if there is no migration in progress?
if mi.Migration != nil {
migration := mi.Migration
startTime := migration.StartTime()
endTime := new(time.Time)
*endTime = migration.EndTime()
var zero time.Time
if *endTime == zero {
endTime = nil
}

summary.Migration = &params.ModelMigrationStatus{
Status: migration.StatusMessage(),
Start: &startTime,
End: endTime,
}
}

result.Results = append(result.Results, params.ModelSummaryResult{Result: summary})
}
return result, nil
Expand Down
2 changes: 1 addition & 1 deletion apiserver/params/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ type ModelSummaryResults struct {
Results []ModelSummaryResult `json:"results"`
}

// ModelSummariesRequest encapsulates how we request a list of model summaries
// ModelSummariesRequest encapsulates how we request a list of model summaries.
type ModelSummariesRequest struct {
UserTag string `json:"user-tag"`
All bool `json:"all,omitempty"`
Expand Down
Loading

0 comments on commit 1260956

Please sign in to comment.