yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/monitor.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package esxi 16 17 import ( 18 "fmt" 19 "time" 20 21 "github.com/vmware/govmomi/object" 22 "github.com/vmware/govmomi/performance" 23 "github.com/vmware/govmomi/view" 24 "github.com/vmware/govmomi/vim25/types" 25 26 "yunion.io/x/jsonutils" 27 "yunion.io/x/log" 28 "yunion.io/x/pkg/errors" 29 30 "yunion.io/x/cloudmux/pkg/cloudprovider" 31 ) 32 33 const ( 34 MONTYPE_HOSTSYSTEM = "HostSystem" 35 MONTYPE_VIRTUALMACHINE = "VirtualMachine" 36 ) 37 38 func (self *SESXiClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 39 metricName := "" 40 switch opts.MetricType { 41 case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: 42 metricName = "cpu.usage.average" 43 case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: 44 metricName = "mem.usage.average" 45 case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: 46 metricName = "net.bytesRx.average" 47 case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: 48 metricName = "net.bytesTx.average" 49 case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: 50 metricName = "disk.read.average" 51 case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: 52 metricName = "disk.write.average" 53 default: 54 return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) 55 } 56 return self.getEcsMetrics(metricName, opts.MetricType, opts.StartTime, opts.EndTime) 57 } 58 59 func (self *SESXiClient) getEcsMetrics(metricName string, metricType cloudprovider.TMetricType, start, end time.Time) ([]cloudprovider.MetricValues, error) { 60 m := view.NewManager(self.client.Client) 61 v, err := m.CreateContainerView(self.context, self.client.Client.ServiceContent.RootFolder, nil, true) 62 if err != nil { 63 return nil, errors.Wrapf(err, "CreateContainerView") 64 } 65 vms, err := v.Find(self.context, []string{MONTYPE_VIRTUALMACHINE}, nil) 66 if err != nil { 67 return nil, err 68 } 69 perfManager := performance.NewManager(self.client.Client) 70 counterInfo, err := perfManager.CounterInfoByName(self.context) 71 if err != nil { 72 return nil, errors.Wrapf(err, "CounterInfoByName") 73 } 74 75 counter, ok := counterInfo[metricName] 76 if !ok { 77 return nil, fmt.Errorf("not found %s", metricName) 78 } 79 80 queries := []types.PerfQuerySpec{} 81 for i := range vms { 82 query := types.PerfQuerySpec{ 83 Entity: vms[i].Reference(), 84 MetricId: []types.PerfMetricId{ 85 { 86 CounterId: counter.Key, 87 }, 88 }, 89 Format: "normal", 90 IntervalId: 20, 91 StartTime: &start, 92 EndTime: &end, 93 } 94 queries = append(queries, query) 95 } 96 97 sample, err := perfManager.Query(self.context, queries) 98 if err != nil { 99 return nil, err 100 } 101 102 result, err := perfManager.ToMetricSeries(self.context, sample) 103 if err != nil { 104 return nil, err 105 } 106 107 ret := []cloudprovider.MetricValues{} 108 for _, metric := range result { 109 vm := object.NewVirtualMachine(self.client.Client, metric.Entity) 110 metricValue := cloudprovider.MetricValues{} 111 metricValue.MetricType = metricType 112 metricValue.Id = vm.UUID(self.context) 113 if len(metric.Value) == 0 { 114 continue 115 } 116 for i, v := range metric.SampleInfo { 117 if v.Timestamp.Second() != 0 { 118 continue 119 } 120 var value float64 121 if len(metric.Value[0].Value) > i { 122 value = float64(metric.Value[0].Value[i]) 123 } 124 switch counter.UnitInfo.GetElementDescription().Key { 125 case "percent": 126 value = value / 100.0 127 case "kiloBytesPerSecond": 128 value = value * 1024.0 129 default: 130 log.Errorf("unknow unit: %s", counter.UnitInfo.GetElementDescription().Key) 131 } 132 metricValue.Values = append(metricValue.Values, cloudprovider.MetricValue{ 133 Timestamp: v.Timestamp, 134 Value: value, 135 }) 136 } 137 ret = append(ret, metricValue) 138 } 139 return ret, nil 140 } 141 142 func (self *SESXiClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 143 metricName := "" 144 switch opts.MetricType { 145 case cloudprovider.HOST_METRIC_TYPE_CPU_USAGE: 146 metricName = "cpu.usage.average" 147 case cloudprovider.HOST_METRIC_TYPE_MEM_USAGE: 148 metricName = "mem.usage.average" 149 case cloudprovider.HOST_METRIC_TYPE_NET_BPS_RX: 150 metricName = "net.received.average" 151 case cloudprovider.HOST_METRIC_TYPE_NET_BPS_TX: 152 metricName = "net.transmitted.average" 153 case cloudprovider.HOST_METRIC_TYPE_DISK_IO_READ_BPS: 154 metricName = "disk.read.average" 155 case cloudprovider.HOST_METRIC_TYPE_DISK_IO_WRITE_BPS: 156 metricName = "disk.write.average" 157 default: 158 return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) 159 } 160 return self.getHostMetrics(metricName, opts.MetricType, opts.StartTime, opts.EndTime) 161 } 162 163 func (self *SESXiClient) getHostMetrics(metricName string, metricType cloudprovider.TMetricType, start, end time.Time) ([]cloudprovider.MetricValues, error) { 164 m := view.NewManager(self.client.Client) 165 v, err := m.CreateContainerView(self.context, self.client.Client.ServiceContent.RootFolder, nil, true) 166 if err != nil { 167 return nil, errors.Wrapf(err, "CreateContainerView") 168 } 169 vms, err := v.Find(self.context, []string{"HostSystem"}, nil) 170 if err != nil { 171 return nil, err 172 } 173 perfManager := performance.NewManager(self.client.Client) 174 counterInfo, err := perfManager.CounterInfoByName(self.context) 175 if err != nil { 176 return nil, errors.Wrapf(err, "CounterInfoByName") 177 } 178 179 counter, ok := counterInfo[metricName] 180 if !ok { 181 return nil, fmt.Errorf("not found %s", metricName) 182 } 183 keys := []types.PerfMetricId{} 184 for _, v := range counterInfo { 185 keys = append(keys, types.PerfMetricId{ 186 CounterId: v.Key, 187 }) 188 } 189 190 queries := []types.PerfQuerySpec{} 191 for i := range vms { 192 query := types.PerfQuerySpec{ 193 Entity: vms[i].Reference(), 194 MetricId: []types.PerfMetricId{ 195 { 196 CounterId: counter.Key, 197 }, 198 }, 199 Format: "normal", 200 IntervalId: 0, 201 StartTime: &start, 202 EndTime: &end, 203 } 204 queries = append(queries, query) 205 } 206 207 sample, err := perfManager.Query(self.context, queries) 208 if err != nil { 209 return nil, err 210 } 211 212 result, err := perfManager.ToMetricSeries(self.context, sample) 213 if err != nil { 214 return nil, err 215 } 216 217 dcs, err := self.GetDatacenters() 218 if err != nil { 219 return nil, err 220 } 221 hostMap := map[string]string{} 222 for i := range dcs { 223 if dcs[i] == nil { 224 continue 225 } 226 part, err := dcs[i].GetIHosts() 227 if err != nil { 228 continue 229 } 230 for j := range part { 231 host := part[j].(*SHost) 232 hostMap[host.GetId()] = host.GetGlobalId() 233 } 234 } 235 236 ret := []cloudprovider.MetricValues{} 237 for _, metric := range result { 238 metricValue := cloudprovider.MetricValues{} 239 metricValue.MetricType = metricType 240 hostId, ok := hostMap[metric.Entity.Value] 241 if !ok { 242 continue 243 } 244 metricValue.Id = hostId 245 if len(metric.Value) == 0 { 246 continue 247 } 248 for i, v := range metric.SampleInfo { 249 if v.Timestamp.Second() != 0 { 250 continue 251 } 252 var value float64 253 if len(metric.Value[0].Value) > i { 254 value = float64(metric.Value[0].Value[i]) 255 } 256 switch counter.UnitInfo.GetElementDescription().Key { 257 case "percent": 258 value = value / 100.0 259 case "kiloBytesPerSecond": 260 value = value * 1024.0 261 default: 262 log.Errorf("unknow unit: %s", counter.UnitInfo.GetElementDescription().Key) 263 } 264 metricValue.Values = append(metricValue.Values, cloudprovider.MetricValue{ 265 Timestamp: v.Timestamp, 266 Value: value, 267 }) 268 } 269 ret = append(ret, metricValue) 270 } 271 return ret, nil 272 } 273 274 func (self *SESXiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 275 switch opts.ResourceType { 276 case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: 277 return self.GetEcsMetrics(opts) 278 case cloudprovider.METRIC_RESOURCE_TYPE_HOST: 279 return self.GetHostMetrics(opts) 280 default: 281 return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) 282 } 283 } 284 285 func (self *SESXiClient) GetMetricTypes() (jsonutils.JSONObject, error) { 286 perfManager := performance.NewManager(self.client.Client) 287 counterInfo, err := perfManager.CounterInfoByName(self.context) 288 if err != nil { 289 return nil, errors.Wrapf(err, "CounterInfoByName") 290 } 291 return jsonutils.Marshal(counterInfo), nil 292 }