github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/payloadshookcontext/unitfacade.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package payloadshookcontext 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 "gopkg.in/juju/names.v2" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/payload" 14 "github.com/juju/juju/payload/api" 15 "github.com/juju/juju/state" 16 ) 17 18 var logger = loggo.GetLogger("juju.apiserver.payloadshookcontext") 19 20 // NewHookContextFacade returns a new payloads hook context facade for 21 // the State and Unit given. It is used for facade registration. 22 func NewHookContextFacade(st *state.State, unit *state.Unit) (interface{}, error) { 23 up, err := st.UnitPayloads(unit) 24 if err != nil { 25 return nil, errors.Trace(err) 26 } 27 return NewUnitFacade(up), nil 28 } 29 30 // UnitPayloadBackend exposes the State functionality for a unit's payloads. 31 type UnitPayloadBackend interface { 32 // Track tracks a payload for the unit and info. 33 Track(info payload.Payload) error 34 35 // List returns information on the payload with the id on the unit. 36 List(ids ...string) ([]payload.Result, error) 37 38 // Settatus sets the status for the payload with the given id on the unit. 39 SetStatus(id, status string) error 40 41 // LookUp returns the payload ID for the given name/rawID pair. 42 LookUp(name, rawID string) (string, error) 43 44 // Untrack removes the information for the payload with the given id. 45 Untrack(id string) error 46 } 47 48 // UnitFacade serves payload-specific API methods. 49 type UnitFacade struct { 50 backend UnitPayloadBackend 51 } 52 53 // NewUnitFacade builds a new facade for the given backend. 54 func NewUnitFacade(backend UnitPayloadBackend) *UnitFacade { 55 return &UnitFacade{backend: backend} 56 } 57 58 // Track stores a payload to be tracked in state. 59 func (uf UnitFacade) Track(args params.TrackPayloadArgs) (params.PayloadResults, error) { 60 logger.Debugf("tracking %d payloads from API", len(args.Payloads)) 61 62 var r params.PayloadResults 63 for _, apiPayload := range args.Payloads { 64 pl, err := api.API2Payload(apiPayload) 65 if err != nil { 66 return r, errors.Trace(err) 67 } 68 logger.Debugf("tracking payload from API: %#v", pl) 69 70 id, err := uf.track(pl.Payload) 71 res := newPayloadResult(id, err) 72 r.Results = append(r.Results, res) 73 } 74 return r, nil 75 } 76 77 func (uf UnitFacade) track(pl payload.Payload) (string, error) { 78 if err := uf.backend.Track(pl); err != nil { 79 return "", errors.Trace(err) 80 } 81 id, err := uf.backend.LookUp(pl.Name, pl.ID) 82 if err != nil { 83 return "", errors.Trace(err) 84 } 85 return id, nil 86 } 87 88 // List builds the list of payload being tracked for 89 // the given unit and IDs. If no IDs are provided then all tracked 90 // payloads for the unit are returned. 91 func (uf UnitFacade) List(args params.Entities) (params.PayloadResults, error) { 92 if len(args.Entities) == 0 { 93 return uf.listAll() 94 } 95 96 var ids []string 97 for _, entity := range args.Entities { 98 id, err := api.API2ID(entity.Tag) 99 if err != nil { 100 return params.PayloadResults{}, errors.Trace(err) 101 } 102 ids = append(ids, id) 103 } 104 105 results, err := uf.backend.List(ids...) 106 if err != nil { 107 return params.PayloadResults{}, errors.Trace(err) 108 } 109 110 var r params.PayloadResults 111 for _, result := range results { 112 res := Result2api(result) 113 r.Results = append(r.Results, res) 114 } 115 return r, nil 116 } 117 118 func (uf UnitFacade) listAll() (params.PayloadResults, error) { 119 var r params.PayloadResults 120 121 results, err := uf.backend.List() 122 if err != nil { 123 return r, errors.Trace(err) 124 } 125 126 for _, result := range results { 127 pl := result.Payload 128 id, err := uf.backend.LookUp(pl.Name, pl.ID) 129 if err != nil { 130 logger.Errorf("failed to look up ID for %q: %v", pl.FullID(), err) 131 id = "" 132 } 133 apipl := api.Payload2api(*pl) 134 135 res := newPayloadResult(id, nil) 136 res.Payload = &apipl 137 r.Results = append(r.Results, res) 138 } 139 return r, nil 140 } 141 142 // LookUp identifies the payload with the provided name and raw ID. 143 func (uf UnitFacade) LookUp(args params.LookUpPayloadArgs) (params.PayloadResults, error) { 144 var r params.PayloadResults 145 for _, arg := range args.Args { 146 id, err := uf.backend.LookUp(arg.Name, arg.ID) 147 res := newPayloadResult(id, err) 148 r.Results = append(r.Results, res) 149 } 150 return r, nil 151 } 152 153 // SetStatus sets the raw status of a payload. 154 func (uf UnitFacade) SetStatus(args params.SetPayloadStatusArgs) (params.PayloadResults, error) { 155 var r params.PayloadResults 156 for _, arg := range args.Args { 157 id, err := api.API2ID(arg.Tag) 158 if err != nil { 159 return r, errors.Trace(err) 160 } 161 162 err = uf.backend.SetStatus(id, arg.Status) 163 res := newPayloadResult(id, err) 164 r.Results = append(r.Results, res) 165 } 166 return r, nil 167 } 168 169 // Untrack marks the identified payload as no longer being tracked. 170 func (uf UnitFacade) Untrack(args params.Entities) (params.PayloadResults, error) { 171 var r params.PayloadResults 172 for _, entity := range args.Entities { 173 id, err := api.API2ID(entity.Tag) 174 if err != nil { 175 return r, errors.Trace(err) 176 } 177 178 err = uf.backend.Untrack(id) 179 res := newPayloadResult(id, err) 180 r.Results = append(r.Results, res) 181 } 182 return r, nil 183 } 184 185 // newPayloadResult builds a new PayloadResult from the provided tag 186 // and error. NotFound is also set based on the error. 187 func newPayloadResult(id string, err error) params.PayloadResult { 188 result := payload.Result{ 189 ID: id, 190 Payload: nil, 191 NotFound: errors.IsNotFound(err), 192 Error: err, 193 } 194 return Result2api(result) 195 } 196 197 // Result2api converts the payload.Result into a PayloadResult. 198 func Result2api(result payload.Result) params.PayloadResult { 199 res := params.PayloadResult{ 200 NotFound: result.NotFound, 201 } 202 203 if result.ID != "" { 204 res.Tag = names.NewPayloadTag(result.ID).String() 205 } 206 207 if result.Payload != nil { 208 pl := api.Payload2api(*result.Payload) 209 res.Payload = &pl 210 } 211 212 if result.Error != nil { 213 res.Error = common.ServerError(result.Error) 214 } 215 216 return res 217 }