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  }