// APIResult2ServiceResources converts a ResourcesResult into a resource.ServiceResources. func APIResult2ServiceResources(apiResult ResourcesResult) (resource.ServiceResources, error) { var result resource.ServiceResources if apiResult.Error != nil { // TODO(ericsnow) Return the resources too? err := common.RestoreError(apiResult.Error) return resource.ServiceResources{}, errors.Trace(err) } for _, apiRes := range apiResult.Resources { res, err := API2Resource(apiRes) if err != nil { // This could happen if the server is misbehaving // or non-conforming. // TODO(ericsnow) Aggregate errors? return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } result.Resources = append(result.Resources, res) } for _, unitRes := range apiResult.UnitResources { tag, err := names.ParseUnitTag(unitRes.Tag) if err != nil { return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } resNames := map[string]bool{} unitResources := resource.UnitResources{Tag: tag} for _, apiRes := range unitRes.Resources { res, err := API2Resource(apiRes) if err != nil { return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } resNames[res.Name] = true unitResources.Resources = append(unitResources.Resources, res) } if len(unitRes.DownloadProgress) > 0 { unitResources.DownloadProgress = make(map[string]int64) for resName, progress := range unitRes.DownloadProgress { if _, ok := resNames[resName]; !ok { err := errors.Errorf("got progress from unrecognized resource %q", resName) return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } unitResources.DownloadProgress[resName] = progress } } result.UnitResources = append(result.UnitResources, unitResources) } for _, chRes := range apiResult.CharmStoreResources { res, err := API2CharmResource(chRes) if err != nil { return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } result.CharmStoreResources = append(result.CharmStoreResources, res) } return result, nil }
// ListResources returns the info for each non-pending resource of the // identified service. func (p ResourcePersistence) ListResources(serviceID string) (resource.ServiceResources, error) { logger.Tracef("listing all resources for service %q", serviceID) docs, err := p.resources(serviceID) if err != nil { return resource.ServiceResources{}, errors.Trace(err) } store := map[string]charmresource.Resource{} units := map[names.UnitTag][]resource.Resource{} downloadProgress := make(map[names.UnitTag]map[string]int64) var results resource.ServiceResources for _, doc := range docs { if doc.PendingID != "" { continue } res, err := doc2basicResource(doc) if err != nil { return resource.ServiceResources{}, errors.Trace(err) } if !doc.LastPolled.IsZero() { store[res.Name] = res.Resource continue } if doc.UnitID == "" { results.Resources = append(results.Resources, res) continue } tag := names.NewUnitTag(doc.UnitID) if doc.PendingID == "" { units[tag] = append(units[tag], res) } if doc.DownloadProgress != nil { if downloadProgress[tag] == nil { downloadProgress[tag] = make(map[string]int64) } downloadProgress[tag][doc.Name] = *doc.DownloadProgress } } for _, res := range results.Resources { storeRes := store[res.Name] results.CharmStoreResources = append(results.CharmStoreResources, storeRes) } for tag, res := range units { results.UnitResources = append(results.UnitResources, resource.UnitResources{ Tag: tag, Resources: res, DownloadProgress: downloadProgress[tag], }) } return results, nil }
func (s *ServiceResourcesSuite) TestUpdatesUploaded(c *gc.C) { csRes := newStoreResource(c, "spam", "a-service", 2) res := csRes // a copy res.Origin = charmresource.OriginUpload sr := resource.ServiceResources{ Resources: []resource.Resource{ res, }, CharmStoreResources: []charmresource.Resource{ csRes.Resource, }, } updates, err := sr.Updates() c.Assert(err, jc.ErrorIsNil) c.Check(updates, gc.HasLen, 0) }
func newPersistenceResources(c *gc.C, serviceID string, names ...string) (resource.ServiceResources, []resourceDoc) { var svcResources resource.ServiceResources var docs []resourceDoc for _, name := range names { res, doc := newPersistenceResource(c, serviceID, name) svcResources.Resources = append(svcResources.Resources, res.Resource) svcResources.CharmStoreResources = append(svcResources.CharmStoreResources, res.Resource.Resource) docs = append(docs, doc) csDoc := doc // a copy csDoc.DocID += "#charmstore" csDoc.Username = "" csDoc.Timestamp = coretesting.ZeroTime() csDoc.StoragePath = "" csDoc.LastPolled = coretesting.NonZeroTime().UTC() docs = append(docs, csDoc) } return svcResources, docs }
func (s *ServiceResourcesSuite) TestUpdatesNone(c *gc.C) { spam := newStoreResource(c, "spam", "a-service", 2) eggs := newStoreResource(c, "eggs", "a-service", 3) sr := resource.ServiceResources{ Resources: []resource.Resource{ spam, eggs, }, CharmStoreResources: []charmresource.Resource{ spam.Resource, eggs.Resource, }, } updates, err := sr.Updates() c.Assert(err, jc.ErrorIsNil) c.Check(updates, gc.HasLen, 0) }
func formatServiceResources(sr resource.ServiceResources) (FormattedServiceInfo, error) { var formatted FormattedServiceInfo updates, err := sr.Updates() if err != nil { return formatted, errors.Trace(err) } formatted = FormattedServiceInfo{ Resources: make([]FormattedSvcResource, len(sr.Resources)), Updates: make([]FormattedCharmResource, len(updates)), } for i, r := range sr.Resources { formatted.Resources[i] = FormatSvcResource(r) } for i, u := range updates { formatted.Updates[i] = FormatCharmResource(u) } return formatted, nil }
// FormatServiceDetails converts a ServiceResources value into a formatted value // for display on the command line. func FormatServiceDetails(sr resource.ServiceResources) (FormattedServiceDetails, error) { var formatted FormattedServiceDetails details, err := detailedResources("", sr) if err != nil { return formatted, errors.Trace(err) } updates, err := sr.Updates() if err != nil { return formatted, errors.Trace(err) } formatted = FormattedServiceDetails{ Resources: details, Updates: make([]FormattedCharmResource, len(updates)), } for i, u := range updates { formatted.Updates[i] = FormatCharmResource(u) } return formatted, nil }
func (s *ServiceResourcesSuite) TestUpdatesBadOrdering(c *gc.C) { spam := newStoreResource(c, "spam", "a-service", 2) eggs := newStoreResource(c, "eggs", "a-service", 3) expected := eggs.Resource expected.Revision += 1 sr := resource.ServiceResources{ Resources: []resource.Resource{ spam, eggs, }, CharmStoreResources: []charmresource.Resource{ expected, spam.Resource, }, } updates, err := sr.Updates() c.Assert(err, jc.ErrorIsNil) c.Check(updates, jc.DeepEquals, []charmresource.Resource{expected}) }
// APIResult2ServiceResources converts a ResourcesResult into a resource.ServiceResources. func APIResult2ServiceResources(apiResult ResourcesResult) (resource.ServiceResources, error) { var result resource.ServiceResources if apiResult.Error != nil { // TODO(ericsnow) Return the resources too? err, _ := common.RestoreError(apiResult.Error) return resource.ServiceResources{}, errors.Trace(err) } for _, apiRes := range apiResult.Resources { res, err := API2Resource(apiRes) if err != nil { // This could happen if the server is misbehaving // or non-conforming. // TODO(ericsnow) Aggregate errors? return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } result.Resources = append(result.Resources, res) } for _, unitRes := range apiResult.UnitResources { tag, err := names.ParseUnitTag(unitRes.Tag) if err != nil { return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } unitResources := resource.UnitResources{Tag: tag} for _, apiRes := range unitRes.Resources { res, err := API2Resource(apiRes) if err != nil { return resource.ServiceResources{}, errors.Annotate(err, "got bad data from server") } unitResources.Resources = append(unitResources.Resources, res) } result.UnitResources = append(result.UnitResources, unitResources) } return result, nil }