github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/caasoperator/client.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperator 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/version" 9 "gopkg.in/juju/charm.v6" 10 "gopkg.in/juju/names.v2" 11 12 "github.com/juju/juju/api/base" 13 "github.com/juju/juju/api/common" 14 apiwatcher "github.com/juju/juju/api/watcher" 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/core/life" 17 "github.com/juju/juju/core/model" 18 "github.com/juju/juju/core/status" 19 "github.com/juju/juju/core/watcher" 20 ) 21 22 // Client allows access to the CAAS operator API endpoint. 23 type Client struct { 24 facade base.FacadeCaller 25 *common.APIAddresser 26 } 27 28 // NewClient returns a client used to access the CAAS Operator API. 29 func NewClient(caller base.APICaller) *Client { 30 facadeCaller := base.NewFacadeCaller(caller, "CAASOperator") 31 return &Client{ 32 facade: facadeCaller, 33 APIAddresser: common.NewAPIAddresser(facadeCaller), 34 } 35 } 36 37 func (c *Client) appTag(application string) (names.ApplicationTag, error) { 38 if !names.IsValidApplication(application) { 39 return names.ApplicationTag{}, errors.NotValidf("application name %q", application) 40 } 41 return names.NewApplicationTag(application), nil 42 } 43 44 // Model returns the model entity. 45 func (c *Client) Model() (*model.Model, error) { 46 var result params.ModelResult 47 err := c.facade.FacadeCall("CurrentModel", nil, &result) 48 if err != nil { 49 return nil, err 50 } 51 if err := result.Error; err != nil { 52 return nil, err 53 } 54 modelType := model.ModelType(result.Type) 55 if modelType == "" { 56 modelType = model.IAAS 57 } 58 return &model.Model{ 59 Name: result.Name, 60 UUID: result.UUID, 61 ModelType: modelType, 62 }, nil 63 } 64 65 // SetStatus sets the status of the specified application. 66 func (c *Client) SetStatus( 67 application string, 68 status status.Status, 69 info string, 70 data map[string]interface{}, 71 ) error { 72 tag, err := c.appTag(application) 73 if err != nil { 74 return errors.Trace(err) 75 } 76 var result params.ErrorResults 77 args := params.SetStatus{ 78 Entities: []params.EntityStatusArgs{{ 79 Tag: tag.String(), 80 Status: status.String(), 81 Info: info, 82 Data: data, 83 }}, 84 } 85 if err := c.facade.FacadeCall("SetStatus", args, &result); err != nil { 86 return errors.Trace(err) 87 } 88 return result.OneError() 89 } 90 91 // Charm returns information about the charm currently assigned 92 // to the application, including url, force upgrade and sha etc. 93 func (c *Client) Charm(application string) (_ *charm.URL, forceUpgrade bool, sha256 string, vers int, _ error) { 94 tag, err := c.appTag(application) 95 if err != nil { 96 return nil, false, "", 0, errors.Trace(err) 97 } 98 var results params.ApplicationCharmResults 99 args := params.Entities{ 100 Entities: []params.Entity{{Tag: tag.String()}}, 101 } 102 if err := c.facade.FacadeCall("Charm", args, &results); err != nil { 103 return nil, false, "", 0, errors.Trace(err) 104 } 105 if n := len(results.Results); n != 1 { 106 return nil, false, "", 0, errors.Errorf("expected 1 result, got %d", n) 107 } 108 if err := results.Results[0].Error; err != nil { 109 return nil, false, "", 0, errors.Trace(err) 110 } 111 result := results.Results[0].Result 112 curl, err := charm.ParseURL(result.URL) 113 if err != nil { 114 return nil, false, "", 0, errors.Trace(err) 115 } 116 return curl, result.ForceUpgrade, result.SHA256, result.CharmModifiedVersion, nil 117 } 118 119 // SetPodSpec sets the pod spec of the specified application. 120 func (c *Client) SetPodSpec(appName string, spec string) error { 121 tag, err := applicationTag(appName) 122 if err != nil { 123 return errors.Trace(err) 124 } 125 var result params.ErrorResults 126 args := params.SetPodSpecParams{ 127 Specs: []params.EntityString{{ 128 Tag: tag.String(), 129 Value: spec, 130 }}, 131 } 132 if err := c.facade.FacadeCall("SetPodSpec", args, &result); err != nil { 133 return errors.Trace(err) 134 } 135 return result.OneError() 136 } 137 138 func applicationTag(application string) (names.ApplicationTag, error) { 139 if !names.IsValidApplication(application) { 140 return names.ApplicationTag{}, errors.NotValidf("application name %q", application) 141 } 142 return names.NewApplicationTag(application), nil 143 } 144 145 // Watch returns a watcher for observing changes to an application. 146 func (c *Client) Watch(application string) (watcher.NotifyWatcher, error) { 147 tag, err := c.appTag(application) 148 if err != nil { 149 return nil, errors.Trace(err) 150 } 151 return common.Watch(c.facade, "Watch", tag) 152 } 153 154 func entities(tags ...names.Tag) params.Entities { 155 entities := params.Entities{ 156 Entities: make([]params.Entity, len(tags)), 157 } 158 for i, tag := range tags { 159 entities.Entities[i].Tag = tag.String() 160 } 161 return entities 162 } 163 164 // WatchUnits returns a StringsWatcher that notifies of 165 // changes to the lifecycles of units of the specified 166 // CAAS application in the current model. 167 func (c *Client) WatchUnits(application string) (watcher.StringsWatcher, error) { 168 applicationTag, err := applicationTag(application) 169 if err != nil { 170 return nil, errors.Trace(err) 171 } 172 args := entities(applicationTag) 173 174 var results params.StringsWatchResults 175 if err := c.facade.FacadeCall("WatchUnits", args, &results); err != nil { 176 return nil, err 177 } 178 if n := len(results.Results); n != 1 { 179 return nil, errors.Errorf("expected 1 result, got %d", n) 180 } 181 if err := results.Results[0].Error; err != nil { 182 return nil, errors.Trace(err) 183 } 184 w := apiwatcher.NewStringsWatcher(c.facade.RawAPICaller(), results.Results[0]) 185 return w, nil 186 } 187 188 // RemoveUnit removes the specified unit from the current model. 189 func (c *Client) RemoveUnit(unitName string) error { 190 if !names.IsValidUnit(unitName) { 191 return errors.NotValidf("unit name %q", unitName) 192 } 193 var result params.ErrorResults 194 args := params.Entities{ 195 Entities: []params.Entity{{Tag: names.NewUnitTag(unitName).String()}}, 196 } 197 err := c.facade.FacadeCall("Remove", args, &result) 198 if err != nil { 199 return err 200 } 201 return result.OneError() 202 } 203 204 // Life returns the lifecycle state for the specified CAAS application 205 // or unit in the current model. 206 func (c *Client) Life(entityName string) (life.Value, error) { 207 var tag names.Tag 208 switch { 209 case names.IsValidApplication(entityName): 210 tag = names.NewApplicationTag(entityName) 211 case names.IsValidUnit(entityName): 212 tag = names.NewUnitTag(entityName) 213 default: 214 return "", errors.NotValidf("application or unit name %q", entityName) 215 } 216 args := entities(tag) 217 218 var results params.LifeResults 219 if err := c.facade.FacadeCall("Life", args, &results); err != nil { 220 return "", err 221 } 222 if n := len(results.Results); n != 1 { 223 return "", errors.Errorf("expected 1 result, got %d", n) 224 } 225 if err := results.Results[0].Error; err != nil { 226 return "", maybeNotFound(err) 227 } 228 return life.Value(results.Results[0].Life), nil 229 } 230 231 // maybeNotFound returns an error satisfying errors.IsNotFound 232 // if the supplied error has a CodeNotFound error. 233 func maybeNotFound(err *params.Error) error { 234 if err == nil || !params.IsCodeNotFound(err) { 235 return err 236 } 237 return errors.NewNotFound(err, "") 238 } 239 240 // SetVersion sets the tools version associated with 241 // the given application. 242 func (c *Client) SetVersion(appName string, v version.Binary) error { 243 if !names.IsValidApplication(appName) { 244 return errors.NotValidf("application name %q", appName) 245 } 246 var results params.ErrorResults 247 args := params.EntitiesVersion{ 248 AgentTools: []params.EntityVersion{{ 249 Tag: names.NewApplicationTag(appName).String(), 250 Tools: ¶ms.Version{v}, 251 }}, 252 } 253 err := c.facade.FacadeCall("SetTools", args, &results) 254 if err != nil { 255 return errors.Trace(err) 256 } 257 return results.OneError() 258 }