func (c *UnitFacadeClient) getResourceInfo(resourceName string) (resource.Resource, error) { var response private.ResourcesResult args := private.ListResourcesArgs{ ResourceNames: []string{resourceName}, } if err := c.FacadeCall("GetResourceInfo", &args, &response); err != nil { return resource.Resource{}, errors.Annotate(err, "could not get resource info") } if response.Error != nil { err, _ := common.RestoreError(response.Error) return resource.Resource{}, errors.Annotate(err, "request failed on server") } if len(response.Resources) != 1 { return resource.Resource{}, errors.New("got bad response from API server") } if response.Resources[0].Error != nil { err, _ := common.RestoreError(response.Error) return resource.Resource{}, errors.Annotate(err, "request failed for resource") } res, err := api.API2Resource(response.Resources[0].Resource) if err != nil { return resource.Resource{}, errors.Annotate(err, "got bad data from API server") } return res, nil }
// API2Result converts the API result to a payload.Result. func API2Result(r PayloadResult) (payload.Result, error) { result := payload.Result{ NotFound: r.NotFound, } id, err := API2ID(r.Tag) if err != nil { return result, errors.Trace(err) } result.ID = id if r.Payload != nil { pl, err := api.API2Payload(*r.Payload) if err != nil { return result, errors.Trace(err) } result.Payload = &pl } if r.Error != nil { result.Error = common.RestoreError(r.Error) } return result, nil }
// AddPendingResources sends the provided resource info up to Juju // without making it available yet. func (c Client) AddPendingResources(args AddPendingResourcesArgs) (pendingIDs []string, err error) { apiArgs, err := api.NewAddPendingResourcesArgs(args.ServiceID, args.CharmID, args.CharmStoreMacaroon, args.Resources) if err != nil { return nil, errors.Trace(err) } var result api.AddPendingResourcesResult if err := c.FacadeCall("AddPendingResources", &apiArgs, &result); err != nil { return nil, errors.Trace(err) } if result.Error != nil { err := common.RestoreError(result.Error) return nil, errors.Trace(err) } if len(result.PendingIDs) != len(args.Resources) { return nil, errors.Errorf("bad data from server: expected %d IDs, got %d", len(args.Resources), len(result.PendingIDs)) } for i, id := range result.PendingIDs { if id == "" { return nil, errors.Errorf("bad data from server: got an empty ID for resource %q", args.Resources[i].Name) } // TODO(ericsnow) Do other validation? } return result.PendingIDs, nil }
// GetLastSent makes a "GetLastSent" call on the facade and returns the // results in the same order. func (c LastSentClient) GetLastSent(ids []LastSentID) ([]LastSentResult, error) { var args params.LogForwardingGetLastSentParams args.IDs = make([]params.LogForwardingID, len(ids)) for i, id := range ids { args.IDs[i] = params.LogForwardingID{ ModelTag: id.Model.String(), Sink: id.Sink, } } var apiResults params.LogForwardingGetLastSentResults err := c.caller.FacadeCall("GetLastSent", args, &apiResults) if err != nil { return nil, errors.Trace(err) } results := make([]LastSentResult, len(ids)) for i, apiRes := range apiResults.Results { results[i] = LastSentResult{ LastSentInfo: LastSentInfo{ LastSentID: ids[i], RecordID: apiRes.RecordID, }, Error: common.RestoreError(apiRes.Error), } if apiRes.RecordTimestamp > 0 { results[i].RecordTimestamp = time.Unix(0, apiRes.RecordTimestamp) } } return results, nil }
// SetLastSent makes a "SetLastSent" call on the facade and returns the // results in the same order. func (c LastSentClient) SetLastSent(reqs []LastSentInfo) ([]LastSentResult, error) { var args params.LogForwardingSetLastSentParams args.Params = make([]params.LogForwardingSetLastSentParam, len(reqs)) for i, req := range reqs { args.Params[i] = params.LogForwardingSetLastSentParam{ LogForwardingID: params.LogForwardingID{ ModelTag: req.Model.String(), Sink: req.Sink, }, RecordID: req.RecordID, RecordTimestamp: req.RecordTimestamp.UnixNano(), } } var apiResults params.ErrorResults err := c.caller.FacadeCall("SetLastSent", args, &apiResults) if err != nil { return nil, errors.Trace(err) } results := make([]LastSentResult, len(reqs)) for i, apiRes := range apiResults.Results { results[i] = LastSentResult{ LastSentInfo: reqs[i], Error: common.RestoreError(apiRes.Error), } } return results, nil }
// 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 }
func (s *errorsSuite) TestErrorTransform(c *gc.C) { for i, t := range errorTransformTests { c.Logf("running test %d: %T{%q}", i, t.err, t.err) err1, status := common.ServerErrorAndStatus(t.err) // Sanity check that ServerError returns the same thing. err2 := common.ServerError(t.err) c.Assert(err2, gc.DeepEquals, err1) c.Assert(status, gc.Equals, t.status) if t.err == nil { c.Assert(err1, gc.IsNil) c.Assert(status, gc.Equals, http.StatusOK) continue } c.Assert(err1.Message, gc.Equals, t.err.Error()) c.Assert(err1.Code, gc.Equals, t.code) if t.helperFunc != nil { c.Assert(err1, jc.Satisfies, t.helperFunc) } // TODO(ericsnow) Remove this switch once the other error types are supported. switch t.code { case params.CodeHasAssignedUnits, params.CodeNoAddressSet, params.CodeUpgradeInProgress, params.CodeMachineHasAttachedStorage, params.CodeDischargeRequired: continue case params.CodeNotFound: if common.IsUnknownEnviromentError(t.err) { continue } case params.CodeOperationBlocked: // ServerError doesn't actually have a case for this code. continue } c.Logf(" checking restore (%#v)", err1) restored, ok := common.RestoreError(err1) if t.err == nil { c.Check(ok, jc.IsTrue) c.Check(restored, jc.ErrorIsNil) } else if t.code == "" { c.Check(ok, jc.IsFalse) c.Check(restored.Error(), gc.Equals, t.err.Error()) } else { c.Check(ok, jc.IsTrue) // TODO(ericsnow) Use a stricter DeepEquals check. c.Check(errors.Cause(restored), gc.FitsTypeOf, t.err) c.Check(restored.Error(), gc.Equals, t.err.Error()) } } }
// 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 }
func (s *LastSentSuite) TestGetLastSent(c *gc.C) { stub := &testing.Stub{} caller := &stubFacadeCaller{stub: stub} caller.ReturnFacadeCallGet = params.LogForwardingGetLastSentResults{ Results: []params.LogForwardingGetLastSentResult{{ RecordID: 10, RecordTimestamp: 100, }, { RecordID: 20, RecordTimestamp: 200, }, { Error: common.ServerError(errors.NewNotFound(state.ErrNeverForwarded, "")), }}, } client := logfwd.NewLastSentClient(caller.newFacadeCaller) model := "deadbeef-2f18-4fd2-967d-db9663db7bea" modelTag := names.NewModelTag(model) results, err := client.GetLastSent([]logfwd.LastSentID{{ Model: modelTag, Sink: "spam", }, { Model: modelTag, Sink: "eggs", }, { Model: modelTag, Sink: "ham", }}) c.Assert(err, jc.ErrorIsNil) c.Check(results, jc.DeepEquals, []logfwd.LastSentResult{{ LastSentInfo: logfwd.LastSentInfo{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "spam", }, RecordID: 10, RecordTimestamp: time.Unix(0, 100), }, }, { LastSentInfo: logfwd.LastSentInfo{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "eggs", }, RecordID: 20, RecordTimestamp: time.Unix(0, 200), }, }, { LastSentInfo: logfwd.LastSentInfo{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "ham", }, }, Error: common.RestoreError(¶ms.Error{ Message: `cannot find ID of the last forwarded record`, Code: params.CodeNotFound, }), }}) stub.CheckCallNames(c, "newFacadeCaller", "FacadeCall") stub.CheckCall(c, 0, "newFacadeCaller", "LogForwarding") stub.CheckCall(c, 1, "FacadeCall", "GetLastSent", params.LogForwardingGetLastSentParams{ IDs: []params.LogForwardingID{{ ModelTag: modelTag.String(), Sink: "spam", }, { ModelTag: modelTag.String(), Sink: "eggs", }, { ModelTag: modelTag.String(), Sink: "ham", }}, }) }
func (s *LastSentSuite) TestSetLastSent(c *gc.C) { stub := &testing.Stub{} caller := &stubFacadeCaller{stub: stub} apiError := common.ServerError(errors.New("<failed>")) caller.ReturnFacadeCallSet = params.ErrorResults{ Results: []params.ErrorResult{{ Error: nil, }, { Error: nil, }, { Error: apiError, }}, } client := logfwd.NewLastSentClient(caller.newFacadeCaller) model := "deadbeef-2f18-4fd2-967d-db9663db7bea" modelTag := names.NewModelTag(model) results, err := client.SetLastSent([]logfwd.LastSentInfo{{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "spam", }, RecordID: 10, RecordTimestamp: time.Unix(0, 100), }, { LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "eggs", }, RecordID: 20, RecordTimestamp: time.Unix(0, 200), }, { LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "ham", }, RecordID: 15, RecordTimestamp: time.Unix(0, 150), }}) c.Assert(err, jc.ErrorIsNil) c.Check(results, jc.DeepEquals, []logfwd.LastSentResult{{ LastSentInfo: logfwd.LastSentInfo{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "spam", }, RecordID: 10, RecordTimestamp: time.Unix(0, 100), }, }, { LastSentInfo: logfwd.LastSentInfo{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "eggs", }, RecordID: 20, RecordTimestamp: time.Unix(0, 200), }, }, { LastSentInfo: logfwd.LastSentInfo{ LastSentID: logfwd.LastSentID{ Model: modelTag, Sink: "ham", }, RecordID: 15, RecordTimestamp: time.Unix(0, 150), }, Error: common.RestoreError(apiError), }}) stub.CheckCallNames(c, "newFacadeCaller", "FacadeCall") stub.CheckCall(c, 0, "newFacadeCaller", "LogForwarding") stub.CheckCall(c, 1, "FacadeCall", "SetLastSent", params.LogForwardingSetLastSentParams{ Params: []params.LogForwardingSetLastSentParam{{ LogForwardingID: params.LogForwardingID{ ModelTag: modelTag.String(), Sink: "spam", }, RecordID: 10, RecordTimestamp: 100, }, { LogForwardingID: params.LogForwardingID{ ModelTag: modelTag.String(), Sink: "eggs", }, RecordID: 20, RecordTimestamp: 200, }, { LogForwardingID: params.LogForwardingID{ ModelTag: modelTag.String(), Sink: "ham", }, RecordID: 15, RecordTimestamp: 150, }}, }) }