github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/controller/caasoperatorprovisioner/client.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperatorprovisioner 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names/v5" 9 "github.com/juju/version/v2" 10 11 "github.com/juju/juju/api/base" 12 charmscommon "github.com/juju/juju/api/common/charms" 13 apiwatcher "github.com/juju/juju/api/watcher" 14 "github.com/juju/juju/core/life" 15 "github.com/juju/juju/core/resources" 16 "github.com/juju/juju/core/watcher" 17 "github.com/juju/juju/rpc/params" 18 "github.com/juju/juju/storage" 19 ) 20 21 // Client allows access to the CAAS operator provisioner API endpoint. 22 type Client struct { 23 facade base.FacadeCaller 24 *charmscommon.CharmInfoClient 25 *charmscommon.ApplicationCharmInfoClient 26 } 27 28 // NewClient returns a client used to access the CAAS Operator Provisioner API. 29 func NewClient(caller base.APICaller) *Client { 30 facadeCaller := base.NewFacadeCaller(caller, "CAASOperatorProvisioner") 31 charmInfoClient := charmscommon.NewCharmInfoClient(facadeCaller) 32 appCharmInfoClient := charmscommon.NewApplicationCharmInfoClient(facadeCaller) 33 return &Client{ 34 facade: facadeCaller, 35 CharmInfoClient: charmInfoClient, 36 ApplicationCharmInfoClient: appCharmInfoClient, 37 } 38 } 39 40 // WatchApplications returns a StringsWatcher that notifies of 41 // changes to the lifecycles of CAAS applications in the current model. 42 func (c *Client) WatchApplications() (watcher.StringsWatcher, error) { 43 var result params.StringsWatchResult 44 if err := c.facade.FacadeCall("WatchApplications", nil, &result); err != nil { 45 return nil, err 46 } 47 if err := result.Error; err != nil { 48 return nil, result.Error 49 } 50 w := apiwatcher.NewStringsWatcher(c.facade.RawAPICaller(), result) 51 return w, nil 52 } 53 54 // ApplicationPassword holds parameters for setting 55 // an application password. 56 type ApplicationPassword struct { 57 Name string 58 Password string 59 } 60 61 // SetPasswords sets API passwords for the specified applications. 62 func (c *Client) SetPasswords(appPasswords []ApplicationPassword) (params.ErrorResults, error) { 63 var result params.ErrorResults 64 args := params.EntityPasswords{Changes: make([]params.EntityPassword, len(appPasswords))} 65 for i, p := range appPasswords { 66 args.Changes[i] = params.EntityPassword{ 67 Tag: names.NewApplicationTag(p.Name).String(), Password: p.Password, 68 } 69 } 70 err := c.facade.FacadeCall("SetPasswords", args, &result) 71 if err != nil { 72 return params.ErrorResults{}, err 73 } 74 if len(result.Results) != len(args.Changes) { 75 return params.ErrorResults{}, errors.Errorf("expected %d result(s), got %d", len(args.Changes), len(result.Results)) 76 } 77 return result, nil 78 } 79 80 // maybeNotFound returns an error satisfying errors.IsNotFound 81 // if the supplied error has a CodeNotFound error. 82 func maybeNotFound(err *params.Error) error { 83 if err == nil || !params.IsCodeNotFound(err) { 84 return err 85 } 86 return errors.NewNotFound(err, "") 87 } 88 89 // Life returns the lifecycle state for the specified CAAS application 90 // or unit in the current model. 91 func (c *Client) Life(appName string) (life.Value, error) { 92 if !names.IsValidApplication(appName) { 93 return "", errors.NotValidf("application name %q", appName) 94 } 95 args := params.Entities{ 96 Entities: []params.Entity{{Tag: names.NewApplicationTag(appName).String()}}, 97 } 98 99 var results params.LifeResults 100 if err := c.facade.FacadeCall("Life", args, &results); err != nil { 101 return "", err 102 } 103 if n := len(results.Results); n != 1 { 104 return "", errors.Errorf("expected 1 result, got %d", n) 105 } 106 if err := results.Results[0].Error; err != nil { 107 return "", maybeNotFound(err) 108 } 109 return results.Results[0].Life, nil 110 } 111 112 // OperatorProvisioningInfo holds the info needed to provision an operator. 113 type OperatorProvisioningInfo struct { 114 ImageDetails resources.DockerImageDetails 115 BaseImageDetails resources.DockerImageDetails 116 Version version.Number 117 APIAddresses []string 118 Tags map[string]string 119 CharmStorage *storage.KubernetesFilesystemParams 120 } 121 122 // OperatorProvisioningInfo returns the info needed to provision an operator for an application. 123 func (c *Client) OperatorProvisioningInfo(applicationName string) (OperatorProvisioningInfo, error) { 124 args := params.Entities{Entities: []params.Entity{ 125 {Tag: names.NewApplicationTag(applicationName).String()}, 126 }} 127 var result params.OperatorProvisioningInfoResults 128 if err := c.facade.FacadeCall("OperatorProvisioningInfo", args, &result); err != nil { 129 return OperatorProvisioningInfo{}, err 130 } 131 if len(result.Results) != 1 { 132 return OperatorProvisioningInfo{}, errors.Errorf("expected one result, got %d", len(result.Results)) 133 } 134 info := result.Results[0] 135 if err := info.Error; err != nil { 136 return OperatorProvisioningInfo{}, errors.Trace(err) 137 } 138 return OperatorProvisioningInfo{ 139 ImageDetails: params.ConvertDockerImageInfo(info.ImageDetails), 140 BaseImageDetails: params.ConvertDockerImageInfo(info.BaseImageDetails), 141 Version: info.Version, 142 APIAddresses: info.APIAddresses, 143 Tags: info.Tags, 144 CharmStorage: filesystemFromParams(info.CharmStorage), 145 }, nil 146 } 147 148 func filesystemFromParams(in *params.KubernetesFilesystemParams) *storage.KubernetesFilesystemParams { 149 if in == nil { 150 return nil 151 } 152 return &storage.KubernetesFilesystemParams{ 153 StorageName: in.StorageName, 154 Provider: storage.ProviderType(in.Provider), 155 Size: in.Size, 156 Attributes: in.Attributes, 157 ResourceTags: in.Tags, 158 } 159 } 160 161 // OperatorCertificate provides all the information an operator needs to 162 // create a TLS listener. 163 type OperatorCertificate struct { 164 CACert string 165 Cert string 166 PrivateKey string 167 } 168 169 // IssueOperatorCertificate issues an x509 certificate for use by the specified application operator. 170 func (c *Client) IssueOperatorCertificate(applicationName string) (OperatorCertificate, error) { 171 if !names.IsValidApplication(applicationName) { 172 return OperatorCertificate{}, errors.NotValidf("application name %q", applicationName) 173 } 174 args := params.Entities{Entities: []params.Entity{ 175 {Tag: names.NewApplicationTag(applicationName).String()}, 176 }} 177 var result params.IssueOperatorCertificateResults 178 if err := c.facade.FacadeCall("IssueOperatorCertificate", args, &result); err != nil { 179 return OperatorCertificate{}, errors.Trace(err) 180 } 181 if len(result.Results) != 1 { 182 return OperatorCertificate{}, errors.Errorf("expected one result, got %d", len(result.Results)) 183 } 184 certInfo := result.Results[0] 185 if err := certInfo.Error; err != nil { 186 return OperatorCertificate{}, errors.Trace(err) 187 } 188 return OperatorCertificate{ 189 CACert: certInfo.CACert, 190 Cert: certInfo.Cert, 191 PrivateKey: certInfo.PrivateKey, 192 }, nil 193 }