github.com/vmware/govmomi@v0.51.0/alarm/manager.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package alarm
     6  
     7  import (
     8  	"context"
     9  
    10  	"github.com/vmware/govmomi/event"
    11  	"github.com/vmware/govmomi/find"
    12  	"github.com/vmware/govmomi/object"
    13  	"github.com/vmware/govmomi/property"
    14  	"github.com/vmware/govmomi/vim25"
    15  	"github.com/vmware/govmomi/vim25/methods"
    16  	"github.com/vmware/govmomi/vim25/mo"
    17  	"github.com/vmware/govmomi/vim25/types"
    18  )
    19  
    20  type Manager struct {
    21  	object.Common
    22  
    23  	pc *property.Collector
    24  }
    25  
    26  var Severity = map[types.ManagedEntityStatus]string{
    27  	types.ManagedEntityStatusGray:   "Unknown",
    28  	types.ManagedEntityStatusGreen:  "Normal",
    29  	types.ManagedEntityStatusYellow: "Warning",
    30  	types.ManagedEntityStatusRed:    "Alert",
    31  }
    32  
    33  // GetManager wraps NewManager, returning ErrNotSupported
    34  // when the client is not connected to a vCenter instance.
    35  func GetManager(c *vim25.Client) (*Manager, error) {
    36  	if c.ServiceContent.AlarmManager == nil {
    37  		return nil, object.ErrNotSupported
    38  	}
    39  	return NewManager(c), nil
    40  }
    41  
    42  func NewManager(c *vim25.Client) *Manager {
    43  	m := Manager{
    44  		Common: object.NewCommon(c, *c.ServiceContent.AlarmManager),
    45  		pc:     property.DefaultCollector(c),
    46  	}
    47  
    48  	return &m
    49  }
    50  
    51  func (m Manager) CreateAlarm(ctx context.Context, entity object.Reference, spec types.BaseAlarmSpec) (*types.ManagedObjectReference, error) {
    52  	req := types.CreateAlarm{
    53  		This:   m.Reference(),
    54  		Entity: entity.Reference(),
    55  		Spec:   spec,
    56  	}
    57  
    58  	res, err := methods.CreateAlarm(ctx, m.Client(), &req)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return &res.Returnval, err
    63  }
    64  
    65  func (m Manager) AcknowledgeAlarm(ctx context.Context, alarm types.ManagedObjectReference, entity object.Reference) error {
    66  	req := types.AcknowledgeAlarm{
    67  		This:   m.Reference(),
    68  		Alarm:  alarm,
    69  		Entity: entity.Reference(),
    70  	}
    71  
    72  	_, err := methods.AcknowledgeAlarm(ctx, m.Client(), &req)
    73  
    74  	return err
    75  }
    76  
    77  // GetAlarm returns available alarms defined on the entity.
    78  func (m Manager) GetAlarm(ctx context.Context, entity object.Reference) ([]mo.Alarm, error) {
    79  	req := types.GetAlarm{
    80  		This: m.Reference(),
    81  	}
    82  
    83  	if entity != nil {
    84  		req.Entity = types.NewReference(entity.Reference())
    85  	}
    86  
    87  	res, err := methods.GetAlarm(ctx, m.Client(), &req)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	if len(res.Returnval) == 0 {
    93  		return nil, nil
    94  	}
    95  
    96  	alarms := make([]mo.Alarm, 0, len(res.Returnval))
    97  
    98  	err = m.pc.Retrieve(ctx, res.Returnval, []string{"info"}, &alarms)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return alarms, nil
   104  }
   105  
   106  // StateInfo combines AlarmState with Alarm.Info
   107  type StateInfo struct {
   108  	types.AlarmState
   109  	Info  *types.AlarmInfo `json:"name,omitempty"`
   110  	Path  string           `json:"path,omitempty"`
   111  	Event types.BaseEvent  `json:"event,omitempty"`
   112  }
   113  
   114  // StateInfoOptions for the GetStateInfo method
   115  type StateInfoOptions struct {
   116  	Declared      bool
   117  	InventoryPath bool
   118  	Event         bool
   119  }
   120  
   121  // GetStateInfo combines AlarmState with Alarm.Info
   122  func (m Manager) GetStateInfo(ctx context.Context, entity object.Reference, opts StateInfoOptions) ([]StateInfo, error) {
   123  	prop := "triggeredAlarmState"
   124  	if opts.Declared {
   125  		prop = "declaredAlarmState"
   126  		opts.Event = false
   127  	}
   128  
   129  	var e mo.ManagedEntity
   130  
   131  	err := m.pc.RetrieveOne(ctx, entity.Reference(), []string{prop}, &e)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	var objs []types.ManagedObjectReference
   137  	alarms := append(e.DeclaredAlarmState, e.TriggeredAlarmState...)
   138  	if len(alarms) == 0 {
   139  		return nil, nil
   140  	}
   141  	for i := range alarms {
   142  		objs = append(objs, alarms[i].Alarm)
   143  	}
   144  
   145  	var info []mo.Alarm
   146  	err = m.pc.Retrieve(ctx, objs, []string{"info"}, &info)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	state := make([]StateInfo, len(alarms))
   152  	paths := make(map[types.ManagedObjectReference]string)
   153  
   154  	em := event.NewManager(m.Client())
   155  
   156  	for i, a := range alarms {
   157  		path := paths[a.Entity]
   158  		if opts.InventoryPath {
   159  			if path == "" {
   160  				path, err = find.InventoryPath(ctx, m.Client(), a.Entity)
   161  				if err != nil {
   162  					return nil, err
   163  				}
   164  				paths[a.Entity] = path
   165  			}
   166  		} else {
   167  			path = a.Entity.String()
   168  		}
   169  
   170  		state[i] = StateInfo{
   171  			AlarmState: a,
   172  			Path:       path,
   173  		}
   174  
   175  		for j := range info {
   176  			if info[j].Self == a.Alarm {
   177  				state[i].Info = &info[j].Info
   178  				break
   179  			}
   180  		}
   181  
   182  		if !opts.Event || a.EventKey == 0 {
   183  			continue
   184  		}
   185  
   186  		spec := types.EventFilterSpec{
   187  			EventChainId: a.EventKey,
   188  			Entity: &types.EventFilterSpecByEntity{
   189  				Entity:    a.Entity,
   190  				Recursion: types.EventFilterSpecRecursionOptionSelf,
   191  			},
   192  		}
   193  
   194  		events, err := em.QueryEvents(ctx, spec)
   195  		if err != nil {
   196  			return nil, err
   197  		}
   198  
   199  		for j := range events {
   200  			if events[j].GetEvent().Key == a.EventKey {
   201  				state[i].Event = events[j]
   202  				break
   203  			}
   204  		}
   205  	}
   206  
   207  	return state, nil
   208  }