github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/uniter/application.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names/v5"
    11  
    12  	"github.com/juju/juju/api/common"
    13  	"github.com/juju/juju/core/life"
    14  	"github.com/juju/juju/core/status"
    15  	"github.com/juju/juju/core/watcher"
    16  	"github.com/juju/juju/rpc/params"
    17  )
    18  
    19  // This module implements a subset of the interface provided by
    20  // state.Application, as needed by the uniter API.
    21  
    22  // Application represents the state of an application.
    23  type Application struct {
    24  	st   *State
    25  	tag  names.ApplicationTag
    26  	life life.Value
    27  }
    28  
    29  // Tag returns the application's tag.
    30  func (s *Application) Tag() names.ApplicationTag {
    31  	return s.tag
    32  }
    33  
    34  // Name returns the application name.
    35  func (s *Application) Name() string {
    36  	return s.tag.Id()
    37  }
    38  
    39  // String returns the application as a string.
    40  func (s *Application) String() string {
    41  	return s.Name()
    42  }
    43  
    44  // Watch returns a watcher for observing changes to an application.
    45  func (s *Application) Watch() (watcher.NotifyWatcher, error) {
    46  	return common.Watch(s.st.facade, "Watch", s.tag)
    47  }
    48  
    49  // Life returns the application's current life state.
    50  func (s *Application) Life() life.Value {
    51  	return s.life
    52  }
    53  
    54  // Refresh refreshes the contents of the application from the underlying
    55  // state.
    56  func (s *Application) Refresh() error {
    57  	life, err := s.st.life(s.tag)
    58  	if err != nil {
    59  		return err
    60  	}
    61  	s.life = life
    62  	return nil
    63  }
    64  
    65  // CharmModifiedVersion increments every time the charm, or any part of it, is
    66  // changed in some way.
    67  func (s *Application) CharmModifiedVersion() (int, error) {
    68  	var results params.IntResults
    69  	args := params.Entities{
    70  		Entities: []params.Entity{{Tag: s.tag.String()}},
    71  	}
    72  	err := s.st.facade.FacadeCall("CharmModifiedVersion", args, &results)
    73  	if err != nil {
    74  		return -1, err
    75  	}
    76  
    77  	if len(results.Results) != 1 {
    78  		return -1, fmt.Errorf("expected 1 result, got %d", len(results.Results))
    79  	}
    80  	result := results.Results[0]
    81  	if result.Error != nil {
    82  		return -1, result.Error
    83  	}
    84  
    85  	return result.Result, nil
    86  }
    87  
    88  // CharmURL returns the application's charm URL, and whether units should
    89  // upgrade to the charm with that URL even if they are in an error
    90  // state (force flag).
    91  //
    92  // NOTE: This differs from state.Application.CharmURL() by returning
    93  // an error instead as well, because it needs to make an API call.
    94  func (s *Application) CharmURL() (string, bool, error) {
    95  	var results params.StringBoolResults
    96  	args := params.Entities{
    97  		Entities: []params.Entity{{Tag: s.tag.String()}},
    98  	}
    99  	err := s.st.facade.FacadeCall("CharmURL", args, &results)
   100  	if err != nil {
   101  		return "", false, err
   102  	}
   103  	if len(results.Results) != 1 {
   104  		return "", false, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   105  	}
   106  	result := results.Results[0]
   107  	if result.Error != nil {
   108  		return "", false, result.Error
   109  	}
   110  	if result.Result != "" {
   111  		return result.Result, result.Ok, nil
   112  	}
   113  	return "", false, fmt.Errorf("%q has no charm url set", s.tag)
   114  }
   115  
   116  // SetStatus sets the status of the application if the passed unitName,
   117  // corresponding to the calling unit, is of the leader.
   118  func (s *Application) SetStatus(unitName string, appStatus status.Status, info string, data map[string]interface{}) error {
   119  	tag := names.NewUnitTag(unitName)
   120  	var result params.ErrorResults
   121  	args := params.SetStatus{
   122  		Entities: []params.EntityStatusArgs{
   123  			{
   124  				Tag:    tag.String(),
   125  				Status: appStatus.String(),
   126  				Info:   info,
   127  				Data:   data,
   128  			},
   129  		},
   130  	}
   131  	err := s.st.facade.FacadeCall("SetApplicationStatus", args, &result)
   132  	if err != nil {
   133  		return errors.Trace(err)
   134  	}
   135  	return result.OneError()
   136  }
   137  
   138  // Status returns the status of the application if the passed unitName,
   139  // corresponding to the calling unit, is of the leader.
   140  func (s *Application) Status(unitName string) (params.ApplicationStatusResult, error) {
   141  	tag := names.NewUnitTag(unitName)
   142  	var results params.ApplicationStatusResults
   143  	args := params.Entities{
   144  		Entities: []params.Entity{
   145  			{
   146  				Tag: tag.String(),
   147  			},
   148  		},
   149  	}
   150  	err := s.st.facade.FacadeCall("ApplicationStatus", args, &results)
   151  	if err != nil {
   152  		return params.ApplicationStatusResult{}, errors.Trace(err)
   153  	}
   154  	result := results.Results[0]
   155  	if result.Error != nil {
   156  		return params.ApplicationStatusResult{}, result.Error
   157  	}
   158  	return result, nil
   159  }
   160  
   161  // WatchLeadershipSettings returns a watcher which can be used to wait
   162  // for leadership settings changes to be made for the application.
   163  func (s *Application) WatchLeadershipSettings() (watcher.NotifyWatcher, error) {
   164  	return s.st.LeadershipSettings.WatchLeadershipSettings(s.tag.Id())
   165  }