github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/common/model.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for infos.
     3  
     4  package common
     5  
     6  import (
     7  	"reflect"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/core/model"
    15  	"github.com/juju/juju/core/status"
    16  	"github.com/juju/juju/jujuclient"
    17  )
    18  
    19  // ModelInfo contains information about a model.
    20  type ModelInfo struct {
    21  	// Name is a fully qualified model name, i.e. having the format $owner/$model.
    22  	Name string `json:"name" yaml:"name"`
    23  
    24  	// ShortName is un-qualified model name.
    25  	ShortName      string                      `json:"short-name" yaml:"short-name"`
    26  	UUID           string                      `json:"model-uuid" yaml:"model-uuid"`
    27  	Type           model.ModelType             `json:"model-type" yaml:"model-type"`
    28  	ControllerUUID string                      `json:"controller-uuid" yaml:"controller-uuid"`
    29  	ControllerName string                      `json:"controller-name" yaml:"controller-name"`
    30  	IsController   bool                        `json:"is-controller" yaml:"is-controller"`
    31  	Owner          string                      `json:"owner" yaml:"owner"`
    32  	Cloud          string                      `json:"cloud" yaml:"cloud"`
    33  	CloudRegion    string                      `json:"region,omitempty" yaml:"region,omitempty"`
    34  	ProviderType   string                      `json:"type,omitempty" yaml:"type,omitempty"`
    35  	Life           string                      `json:"life" yaml:"life"`
    36  	Status         *ModelStatus                `json:"status,omitempty" yaml:"status,omitempty"`
    37  	Users          map[string]ModelUserInfo    `json:"users,omitempty" yaml:"users,omitempty"`
    38  	Machines       map[string]ModelMachineInfo `json:"machines,omitempty" yaml:"machines,omitempty"`
    39  	SLA            string                      `json:"sla,omitempty" yaml:"sla,omitempty"`
    40  	SLAOwner       string                      `json:"sla-owner,omitempty" yaml:"sla-owner,omitempty"`
    41  	AgentVersion   string                      `json:"agent-version,omitempty" yaml:"agent-version,omitempty"`
    42  	Credential     *ModelCredential            `json:"credential,omitempty" yaml:"credential,omitempty"`
    43  }
    44  
    45  // ModelMachineInfo contains information about a machine in a model.
    46  // We currently only care about showing core count, but might
    47  // in the future care about memory, disks, containers etc.
    48  type ModelMachineInfo struct {
    49  	Cores uint64 `json:"cores" yaml:"cores"`
    50  }
    51  
    52  // ModelStatus contains the current status of a model.
    53  type ModelStatus struct {
    54  	Current        status.Status `json:"current,omitempty" yaml:"current,omitempty"`
    55  	Message        string        `json:"message,omitempty" yaml:"message,omitempty"`
    56  	Since          string        `json:"since,omitempty" yaml:"since,omitempty"`
    57  	Migration      string        `json:"migration,omitempty" yaml:"migration,omitempty"`
    58  	MigrationStart string        `json:"migration-start,omitempty" yaml:"migration-start,omitempty"`
    59  	MigrationEnd   string        `json:"migration-end,omitempty" yaml:"migration-end,omitempty"`
    60  }
    61  
    62  // ModelUserInfo defines the serialization behaviour of the model user
    63  // information.
    64  type ModelUserInfo struct {
    65  	DisplayName    string `yaml:"display-name,omitempty" json:"display-name,omitempty"`
    66  	Access         string `yaml:"access" json:"access"`
    67  	LastConnection string `yaml:"last-connection" json:"last-connection"`
    68  }
    69  
    70  // FriendlyDuration renders a time pointer that we get from the API as
    71  // a friendly string.
    72  func FriendlyDuration(when *time.Time, now time.Time) string {
    73  	if when == nil {
    74  		return ""
    75  	}
    76  	return UserFriendlyDuration(*when, now)
    77  }
    78  
    79  // ModelCredential contains model credential basic details.
    80  type ModelCredential struct {
    81  	Name  string `json:"name" yaml:"name"`
    82  	Owner string `json:"owner" yaml:"owner"`
    83  	Cloud string `json:"cloud" yaml:"cloud"`
    84  }
    85  
    86  // ModelInfoFromParams translates a params.ModelInfo to ModelInfo.
    87  func ModelInfoFromParams(info params.ModelInfo, now time.Time) (ModelInfo, error) {
    88  	ownerTag, err := names.ParseUserTag(info.OwnerTag)
    89  	if err != nil {
    90  		return ModelInfo{}, errors.Trace(err)
    91  	}
    92  	cloudTag, err := names.ParseCloudTag(info.CloudTag)
    93  	if err != nil {
    94  		return ModelInfo{}, errors.Trace(err)
    95  	}
    96  	modelInfo := ModelInfo{
    97  		ShortName:      info.Name,
    98  		Name:           jujuclient.JoinOwnerModelName(ownerTag, info.Name),
    99  		Type:           model.ModelType(info.Type),
   100  		UUID:           info.UUID,
   101  		ControllerUUID: info.ControllerUUID,
   102  		IsController:   info.IsController,
   103  		Owner:          ownerTag.Id(),
   104  		Life:           string(info.Life),
   105  		Cloud:          cloudTag.Id(),
   106  		CloudRegion:    info.CloudRegion,
   107  	}
   108  	if info.AgentVersion != nil {
   109  		modelInfo.AgentVersion = info.AgentVersion.String()
   110  	}
   111  	// Although this may be more performance intensive, we have to use reflection
   112  	// since structs containing map[string]interface {} cannot be compared, i.e
   113  	// cannot use simple '==' here.
   114  	if !reflect.DeepEqual(info.Status, params.EntityStatus{}) {
   115  		modelInfo.Status = &ModelStatus{
   116  			Current: info.Status.Status,
   117  			Message: info.Status.Info,
   118  			Since:   FriendlyDuration(info.Status.Since, now),
   119  		}
   120  	}
   121  	if info.Migration != nil {
   122  		status := modelInfo.Status
   123  		if status == nil {
   124  			status = &ModelStatus{}
   125  			modelInfo.Status = status
   126  		}
   127  		status.Migration = info.Migration.Status
   128  		status.MigrationStart = FriendlyDuration(info.Migration.Start, now)
   129  		status.MigrationEnd = FriendlyDuration(info.Migration.End, now)
   130  	}
   131  
   132  	if info.ProviderType != "" {
   133  		modelInfo.ProviderType = info.ProviderType
   134  
   135  	}
   136  	if len(info.Users) != 0 {
   137  		modelInfo.Users = ModelUserInfoFromParams(info.Users, now)
   138  	}
   139  	if len(info.Machines) != 0 {
   140  		modelInfo.Machines = ModelMachineInfoFromParams(info.Machines)
   141  	}
   142  	if info.SLA != nil {
   143  		modelInfo.SLA = ModelSLAFromParams(info.SLA)
   144  		modelInfo.SLAOwner = ModelSLAOwnerFromParams(info.SLA)
   145  	}
   146  
   147  	if info.CloudCredentialTag != "" {
   148  		credTag, err := names.ParseCloudCredentialTag(info.CloudCredentialTag)
   149  		if err != nil {
   150  			return ModelInfo{}, errors.Trace(err)
   151  		}
   152  		modelInfo.Credential = &ModelCredential{
   153  			Name:  credTag.Name(),
   154  			Owner: credTag.Owner().Id(),
   155  			Cloud: credTag.Cloud().Id(),
   156  		}
   157  	}
   158  
   159  	return modelInfo, nil
   160  }
   161  
   162  // ModelMachineInfoFromParams translates []params.ModelMachineInfo to a map of
   163  // machine ids to ModelMachineInfo.
   164  func ModelMachineInfoFromParams(machines []params.ModelMachineInfo) map[string]ModelMachineInfo {
   165  	output := make(map[string]ModelMachineInfo, len(machines))
   166  	for _, info := range machines {
   167  		mInfo := ModelMachineInfo{}
   168  		if info.Hardware != nil && info.Hardware.Cores != nil {
   169  			mInfo.Cores = *info.Hardware.Cores
   170  		}
   171  		output[info.Id] = mInfo
   172  	}
   173  	return output
   174  }
   175  
   176  // ModelUserInfoFromParams translates []params.ModelUserInfo to a map of
   177  // user names to ModelUserInfo.
   178  func ModelUserInfoFromParams(users []params.ModelUserInfo, now time.Time) map[string]ModelUserInfo {
   179  	output := make(map[string]ModelUserInfo)
   180  	for _, info := range users {
   181  		outInfo := ModelUserInfo{
   182  			DisplayName: info.DisplayName,
   183  			Access:      string(info.Access),
   184  		}
   185  		if info.LastConnection != nil {
   186  			outInfo.LastConnection = UserFriendlyDuration(*info.LastConnection, now)
   187  		} else {
   188  			outInfo.LastConnection = "never connected"
   189  		}
   190  		output[names.NewUserTag(info.UserName).Id()] = outInfo
   191  	}
   192  	return output
   193  }
   194  
   195  func ModelSLAFromParams(sla *params.ModelSLAInfo) string {
   196  	if sla == nil {
   197  		return ""
   198  	}
   199  	return sla.Level
   200  }
   201  
   202  func ModelSLAOwnerFromParams(sla *params.ModelSLAInfo) string {
   203  	if sla == nil {
   204  		return ""
   205  	}
   206  	return sla.Owner
   207  }
   208  
   209  // OwnerQualifiedModelName returns the model name qualified with the
   210  // model owner if the owner is not the same as the given canonical
   211  // user name. If the owner is a local user, we omit the domain.
   212  func OwnerQualifiedModelName(modelName string, owner, user names.UserTag) string {
   213  	if owner.Id() == user.Id() {
   214  		return modelName
   215  	}
   216  	return jujuclient.JoinOwnerModelName(owner, modelName)
   217  }